PageSourceSearch

https://gts2000.co.kr/theme/basic/js/site-custom.js?ver=2608281751

js gts2000.co.kr collected 2026-10-09 04:14:03 UTC 35,414 bytes, 1,015 lines download raw bytes

1/*
2* File       : site-custom.js
3* Author     : B-WORKER
4*
5*/
6
7jQuery(function($) {
8
9/* 모바일 주소창 표시/숨김으로 인한 viewport resize 시 ScrollTrigger가 pin을 재계산하며 튀는 현상 방지 */
10if(typeof ScrollTrigger !== 'undefined'){
11	ScrollTrigger.config({ ignoreMobileResize: true });
12}
13
14/* **************************************** *
15 * Functions INIT
16 * **************************************** */
17main_visual_slider();
18main_visual_title_reveal();
19main_process_mobile_slider();
20main_process_motion();
21main_process_intro();
22main_pr_motion();
23main_pr_decos();
24main_product_slider();
25site_map_header_state();
26site_map_outside_close();
27site_map_close_btn();
28greeting_intro_pin();
29ceo_img_expand();
30greeting_org_cascade();
31history_decade_motion();
32history_decade_divider_count();
33history_photo_blur();
34overview_counter_parallax();
35overview_cert_tabs();
36location_copy_address();
37business_link_rolling();
38process_step_cycle();
39product_detail_gallery();
40product_list_tabs_scroll();
41sub_title_reveal();
42odometer_count();
43inquery_process_steps();
44
45 /* **************************************** *
46 * script
47 * **************************************** */
48
49function main_visual_slider(){
50	if(!$('.main-visual-container').length){return;}
51
52	// 관리자 등록 슬라이드는 배경을 data-bg로 주입(인라인 style= 미사용)
53	$('.main-visual__bg i[data-bg]').each(function(){
54		this.style.backgroundImage = "url('" + this.getAttribute('data-bg') + "')";
55	});
56
57	new Swiper('.main-visual-container', {
58		slidesPerView:1,
59		speed:600,
60		loop:true,
61		effect:'fade',
62		grabCursor:false,
63		autoplay:{ delay:5000, disableOnInteraction:false },
64		navigation:{ nextEl:'.main-visual .button-next', prevEl:'.main-visual .button-prev' },
65	});
66}
67
68/* 비주얼 히어로 타이틀: 로드 시 단어 단위 마스크업 리빌 */
69function main_visual_title_reveal(){
70	var title = document.querySelector('.js-visual-title');
71	if(!title){ return; }
72	var h2 = title.querySelector('h2');
73	if(!h2){ return; }
74	if(typeof SplitText === 'undefined'){ title.classList.add('is-revealed'); return; }
75	var split = new SplitText(h2, { type: 'lines,words', linesClass: 'mv-line', wordsClass: 'mv-word' });
76	split.words.forEach(function(w, i){ w.style.transitionDelay = (i * 0.09) + 's'; });
77	requestAnimationFrame(function(){
78		requestAnimationFrame(function(){ title.classList.add('is-revealed'); });
79	});
80}
81
82/* main-process: 핀 — 이미지는 대각선 트랙 이동, 번호는 0고정+자릿수 롤러, 텍스트는 글자별 물결 */
83function main_process_motion(){
84	if(typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined'){ return; }
85	var stage = document.querySelector('.main-process__list');
86	if(!stage){ return; }
87	var scaler   = stage.querySelector('.main-process__scaler');
88	var rollInner= stage.querySelector('.main-process__roll-inner');
89	var itemEls  = gsap.utils.toArray('.main-process__item');
90	var N = itemEls.length;
91	if(!scaler || N < 2){ return; }
92	var STEP_X = 520, STEP_Y = 580, IMGWIN = 0.42, T_HOLD = 0.16, T_FADE = 0.06, ROLL_TW = 0.06;
93	function smoothstep(a, b, x){ var t = Math.min(1, Math.max(0, (x - a) / (b - a))); return t * t * (3 - 2 * t); }
94
95	function splitChars(el, splits){
96		if(!el || typeof SplitText === 'undefined'){ return []; }
97		var split = new SplitText(el, { type: 'lines,chars', charsClass: 'mp-char', linesClass: 'mp-line' });
98		splits.push(split);
99		return split.chars || [];
100	}
101
102	var items = itemEls.map(function(el){
103		var title = el.querySelector('.main-process__title');
104		var step  = el.querySelector('.main-process__step');
105		return { img: el.querySelector('.main-process__img'), title: title, step: step,
106			label: el.querySelector('.main-process__label'),
107			stepTitle: el.querySelector('.main-process__step-title'),
108			stepDesc: el.querySelector('.main-process__step-desc'),
109			chars: [] };
110	});
111
112	function setScale(){
113		var scale = Math.min(1, window.innerWidth / 1904);
114		scaler.style.setProperty('--ps', scale);
115		scaler.style.setProperty('--psi', 1 / scale);
116	}
117
118	function render(p){
119		if(rollInner){
120			var idx = 0;
121			for(var m = 1; m < N; m++){ var mid = (m - 0.5) / (N - 1); idx += smoothstep(mid - ROLL_TW, mid + ROLL_TW, p); }
122			rollInner.style.transform = 'translateY(' + (-idx * (100 / N)) + '%)';
123		}
124		for(var i = 0; i < N; i++){
125			var d = Math.abs(p - i / (N - 1));
126			var actImg = 1 - Math.min(d / IMGWIN, 1);
127			var img = items[i].img;
128			img.style.transform = 'translate(' + ((i - p * (N - 1)) * STEP_X) + 'rem,' + ((i - p * (N - 1)) * STEP_Y) + 'rem)';
129			img.style.opacity = (0.12 + 0.88 * actImg).toFixed(3);
130			img.style.filter = 'saturate(' + (0.15 + 0.85 * actImg).toFixed(3) + ')';
131			img.style.zIndex = Math.round(actImg * 10);
132			var r = d <= T_HOLD ? 1 : Math.max(0, 1 - (d - T_HOLD) / T_FADE);
133			if(items[i].label){ var lo = (r - 0.1) / 0.5; items[i].label.style.opacity = lo <= 0 ? '0' : (lo >= 1 ? '1' : lo.toFixed(3)); }
134			var chs = items[i].chars, C = chs.length, SPREAD = Math.max(8, C * 0.5);
135			for(var k = 0; k < C; k++){
136				var o = (r * (C + SPREAD) - k) / SPREAD;
137				chs[k].style.opacity = o <= 0 ? '0' : (o >= 1 ? '1' : o.toFixed(3));
138			}
139		}
140	}
141
142	gsap.matchMedia().add('(min-width:1024px)', function(){
143		var splits = [];
144		items.forEach(function(it){
145			it.chars = splitChars(it.title, splits)
146				.concat(splitChars(it.stepTitle, splits))
147				.concat(splitChars(it.stepDesc, splits));
148			it.title.style.opacity = '1';
149			it.step.style.opacity = '1';
150		});
151		setScale();
152		render(0);
153		window.addEventListener('resize', setScale);
154		var tl = gsap.timeline({
155			scrollTrigger: {
156				trigger: stage,
157				start: 'top top',
158				end: function(){ return '+=' + (window.innerHeight * 2); },
159				pin: true, scrub: 1, invalidateOnRefresh: true,
160				onRefreshInit: setScale,
161				onUpdate: function(self){ render(self.progress); }
162			}
163		});
164		tl.to({}, { duration: 1 });
165
166		return function(){
167			window.removeEventListener('resize', setScale);
168			if(rollInner){ rollInner.style.transform = ''; }
169			items.forEach(function(it){
170				it.img.style.cssText = it.img.style.cssText.replace(/transform[^;]*;?|opacity[^;]*;?|filter[^;]*;?|z-index[^;]*;?/g, '');
171				it.title.style.opacity = ''; it.step.style.opacity = '';
172				if(it.label){ it.label.style.opacity = ''; }
173				it.chars.forEach(function(c){ c.style.opacity = ''; });
174				it.chars = [];
175			});
176			splits.forEach(function(split){ split.revert(); });
177		};
178	});
179}
180
181/* main-process: tablet/mobile slide */
182function main_process_mobile_slider(){
183	if(typeof Swiper === 'undefined'){ return; }
184	var el = document.querySelector('.main-process__scaler');
185	var track = el && el.querySelector('.main-process__track');
186	if(!el || !track){ return; }
187	var descEls = Array.prototype.slice.call(track.querySelectorAll('.main-process__step-desc'));
188	descEls.forEach(function(desc){
189		if(!desc.getAttribute('data-process-original')){
190			desc.setAttribute('data-process-original', desc.innerHTML);
191		}
192	});
193
194	var pagination = el.querySelector('.main-process__pagination');
195	if(!pagination){
196		pagination = document.createElement('div');
197		pagination.className = 'main-process__pagination';
198		el.appendChild(pagination);
199	}
200	var fixedHead = el.querySelector('.main-process__fixed-head');
201	if(!fixedHead){
202		var firstLabel = track.querySelector('.main-process__label');
203		var firstTitle = track.querySelector('.main-process__title');
204		fixedHead = document.createElement('div');
205		fixedHead.className = 'main-process__fixed-head';
206		if(firstLabel){ fixedHead.appendChild(firstLabel.cloneNode(true)); }
207		if(firstTitle){ fixedHead.appendChild(firstTitle.cloneNode(true)); }
208		el.appendChild(fixedHead);
209	}
210	var prevBtn = el.querySelector('.main-process__nav--prev');
211	var nextBtn = el.querySelector('.main-process__nav--next');
212	if(!prevBtn){
213		prevBtn = document.createElement('button');
214		prevBtn.type = 'button';
215		prevBtn.className = 'main-process__nav main-process__nav--prev';
216		prevBtn.setAttribute('aria-label', 'Previous process slide');
217		el.appendChild(prevBtn);
218	}
219	if(!nextBtn){
220		nextBtn = document.createElement('button');
221		nextBtn.type = 'button';
222		nextBtn.className = 'main-process__nav main-process__nav--next';
223		nextBtn.setAttribute('aria-label', 'Next process slide');
224		el.appendChild(nextBtn);
225	}
226
227	var swiper = null;
228	var mq = window.matchMedia('(max-width:1023px)');
229	var compactMq = window.matchMedia('(max-width:540px)');
230
231	function normalizeCompactText(){
232		var compact = compactMq.matches;
233		descEls.forEach(function(desc){
234			var original = desc.getAttribute('data-process-original') || desc.innerHTML;
235			if(compact){
236				var holder = document.createElement('div');
237				holder.innerHTML = original.replace(/<br\s*\/?>/gi, ' ');
238				desc.textContent = holder.textContent.replace(/\s+/g, ' ').trim();
239			}else if(desc.innerHTML !== original){
240				desc.innerHTML = original;
241			}
242		});
243		if(swiper){ swiper.update(); }
244	}
245
246	function enable(){
247		if(swiper){ return; }
248		normalizeCompactText();
249		el.classList.add('main-process__slider');
250		swiper = new Swiper(el, {
251			wrapperClass: 'main-process__track',
252			slideClass: 'main-process__item',
253			slidesPerView: 1,
254			effect: 'fade',
255			fadeEffect: { crossFade: true },
256			speed: 500,
257			loop: false,
258			grabCursor: false,
259			navigation: {
260				prevEl: prevBtn,
261				nextEl: nextBtn,
262				disabledClass: 'main-process__nav--disabled'
263			},
264			pagination: {
265				el: pagination,
266				clickable: true,
267				bulletClass: 'main-process__bullet',
268				bulletActiveClass: 'main-process__bullet--active',
269				renderBullet: function(index, className){
270					return '<button type="button" class="' + className + '" aria-label="Process slide ' + (index + 1) + '"></button>';
271				}
272			}
273		});
274	}
275
276	function disable(){
277		if(!swiper){ return; }
278		swiper.destroy(true, true);
279		swiper = null;
280		el.classList.remove('main-process__slider');
281		normalizeCompactText();
282	}
283
284	function check(){
285		if(mq.matches){ enable(); }
286		else{ disable(); }
287	}
288
289	check();
290	if(mq.addEventListener){ mq.addEventListener('change', check); }
291	else if(mq.addListener){ mq.addListener(check); }
292	if(compactMq.addEventListener){ compactMq.addEventListener('change', normalizeCompactText); }
293	else if(compactMq.addListener){ compactMq.addListener(normalizeCompactText); }
294}
295
296/* main-process intro: 배경선 우측→중앙, 라인 중앙오면 intro pin(100vh) + h2 글자 scrub 진해짐 */
297function main_process_intro(){
298	if(typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined'){ return; }
299	var intro = document.querySelector('.main-process__intro');
300	var line  = document.querySelector('.main-process__bg-line');
301	var h2    = intro && intro.querySelector('h2');
302	if(!intro || !line || !h2 || typeof SplitText === 'undefined'){ return; }
303	gsap.matchMedia().add('(min-width:1024px)', function(){
304		var lineTween = gsap.fromTo(line, { '--pr-vx': 73.95 }, {
305			'--pr-vx': 50, ease: 'none',
306			scrollTrigger: { trigger: intro, start: 'top 45%', end: 'top top', scrub: true }
307		});
308		var split = new SplitText(h2, { type: 'lines,chars', linesClass: 'proc-line', charsClass: 'proc-char' });
309		var charsTween = gsap.fromTo(split.chars, { opacity: 0.1 }, {
310			opacity: 1, ease: 'power1.in', stagger: 0.04,
311			scrollTrigger: { trigger: intro, start: 'top 45%', end: 'top -30%', scrub: true }
312		});
313		return function(){
314			if(lineTween.scrollTrigger){ lineTween.scrollTrigger.kill(); }
315			if(charsTween.scrollTrigger){ charsTween.scrollTrigger.kill(); }
316			lineTween.kill(); charsTween.kill(); split.revert();
317		};
318	});
319}
320
321/* main-pr: 인트로 영상 썸네일이 확대+좌측이동해 다크박스 좌측 영상으로 변신(FLIP) */
322function main_pr_motion(){
323	if(typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined'){ return; }
324	var sec = document.querySelector('.main-pr');
325	if(!sec){ return; }
326	var stage   = sec.querySelector('.main-pr__stage');
327	var introVid= sec.querySelector('.main-pr__intro-video');
328	var boxVid  = sec.querySelector('.main-pr__box-video');
329	var media   = sec.querySelector('.main-pr__media');
330	var intro   = sec.querySelector('.main-pr__intro');
331	var box     = sec.querySelector('.main-pr__box');
332	var stats   = sec.querySelector('.main-pr__stats-wrap');
333	if(!stage || !introVid || !boxVid || !media || !intro || !box || !stats){ return; }
334
335	var r0, r1, scale0, dx, dy;
336	var END = 0.88, BLUR_START = 0.3;
337	function clamp(x){ return x < 0 ? 0 : (x > 1 ? 1 : x); }
338	function measure(){
339		var sb = stage.getBoundingClientRect();
340		var a = introVid.getBoundingClientRect();
341		r0 = { left: a.left - sb.left, top: a.top - sb.top, w: a.width, h: a.height };
342		r1 = { left: 0, top: 0, w: sb.width / 2, h: sb.height };
343		media.style.left = r1.left + 'px'; media.style.top = r1.top + 'px';
344		media.style.width = r1.w + 'px'; media.style.height = r1.h + 'px';
345		scale0 = r0.w / r1.w;
346		dx = r0.left - r1.left;
347		dy = (r0.top - r1.top) + (r0.h - r1.h * scale0) / 2;
348	}
349	function render(p){
350		var m = clamp(p / END);
351		var sc = scale0 + (1 - scale0) * m;
352		media.style.transform = 'translate(' + (dx * (1 - m)).toFixed(2) + 'px,' + (dy * (1 - m)).toFixed(2) + 'px) scale(' + sc.toFixed(4) + ')';
353		media.style.borderRadius = (10 * (1 - m)).toFixed(2) + 'rem';
354		box.style.transform = 'translateY(' + (100 * (1 - m)).toFixed(3) + '%)';
355		var bp = clamp((m - BLUR_START) / (1 - BLUR_START));
356		intro.style.filter = 'blur(' + (bp * 8).toFixed(2) + 'px) brightness(' + (1 - bp * 0.42).toFixed(3) + ')';
357	}
358
359	gsap.matchMedia().add('(min-width:1024px)', function(){
360		sec.classList.add('is-morph');
361		var st = ScrollTrigger.create({
362			trigger: sec, start: 'top top', end: 'bottom bottom',
363			invalidateOnRefresh: true,
364			onUpdate: function(self){ render(self.progress); },
365			onRefresh: function(self){ measure(); render(self.progress); }
366		});
367		requestAnimationFrame(function(){ measure(); render(st.progress); });
368
369		return function(){
370			sec.classList.remove('is-morph');
371			st.kill();
372			media.style.cssText = '';
373			box.style.transform = '';
374			intro.style.opacity = ''; intro.style.filter = ''; stats.style.opacity = ''; stats.style.transform = '';
375		};
376	});
377}
378
379/* main-pr: stat 데코 캔버스 링 모션 — codepen filipz/bNNYyqE 적응 */
380function main_pr_decos(){
381	var hosts = document.querySelectorAll('.main-pr__stat-deco[data-anim]');
382	if(!hosts.length){ return; }
383	var SIZE = 180, DPR = Math.min(window.devicePixelRatio || 1, 2);
384	var visible = true;
385	if('IntersectionObserver' in window){
386		var sec = document.querySelector('.main-pr');
387		if(sec){ new IntersectionObserver(function(e){ visible = e[0].isIntersecting; }, { rootMargin: '120px' }).observe(sec); }
388	}
389
390	var draw = {
391		orbital: function(ctx, cx, cy, t){
392			var orbits = [[15,6],[25,10],[35,14],[45,18],[55,22],[65,26]], maxR = 75;
393			dot(ctx, cx, cy, 3, 0.9);
394			orbits.forEach(function(o){
395				var nr = o[0] / maxR, phase = (t * 0.5 - nr * 1.5) % 1;
396				var pe = Math.sin(phase * Math.PI) * 2; pe = pe > 0 ? pe : 0;
397				for(var i = 0; i < o[1]; i++){
398					var a = i / o[1] * Math.PI * 2, r = o[0] + pe;
399					dot(ctx, cx + Math.cos(a) * r, cy + Math.sin(a) * r, 2 + pe / 2 * 1.5, 0.7 + pe / 2 * 0.3);
400				}
401			});
402		},
403		wave: function(ctx, cx, cy, t){
404			var rings = [[15,6],[30,12],[45,18],[60,24],[75,30]];
405			dot(ctx, cx, cy, 2, 0.9);
406			rings.forEach(function(ring, ri){
407				for(var i = 0; i < ring[1]; i++){
408					var a = i / ring[1] * Math.PI * 2, rp = Math.sin(t * 2 - ri * 0.4) * 3;
409					var op = 0.4 + Math.sin(t * 2 - ri * 0.4 + i * 0.2) * 0.6;
410					dot(ctx, cx + Math.cos(a) * (ring[0] + rp), cy + Math.sin(a) * (ring[0] + rp), 2, op);
411				}
412			});
413		},
414		concentric: function(ctx, cx, cy, t){
415			var rc = 5, maxR = 75;
416			dot(ctx, cx, cy, 3, 0.9);
417			for(var r = 0; r < rc; r++){
418				var radius = (r + 1) / rc * maxR, dc = 6 + r * 6;
419				var po = r % 2 === 0 ? t * 0.2 : -t * 0.2, rp = t + r * 0.7;
420				for(var i = 0; i < dc; i++){
421					var a = i / dc * Math.PI * 2 + po, fr = radius + Math.sin(rp) * 3;
422					var bs = 2 + r / (rc - 1), sz = Math.sin(rp) * bs * 0.7 + bs;
423					dot(ctx, cx + Math.cos(a) * fr, cy + Math.sin(a) * fr, sz, 0.6 + Math.sin(rp) * 0.4);
424				}
425			}
426		},
427		sequential: function(ctx, cx, cy, t){
428			var radius = 70, dc = 16;
429			dot(ctx, cx, cy, 3, 0.9);
430			ring(ctx, cx, cy, radius, 0.05);
431			for(var i = 0; i < dc; i++){
432				var a = i / dc * Math.PI * 2, ph = (t * 0.5 + i / dc) % 1, pf = Math.sin(ph * Math.PI * 2);
433				var fr = radius + pf * 5, x = cx + Math.cos(a) * fr, y = cy + Math.sin(a) * fr;
434				ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(x, y);
435				ctx.strokeStyle = 'rgba(255,255,255,' + (0.1 + pf * 0.2) + ')'; ctx.lineWidth = 1; ctx.stroke();
436				dot(ctx, x, y, 2 + pf * 2, 0.9);
437			}
438		}
439	};
440	function dot(ctx, x, y, r, op){
441		ctx.beginPath(); ctx.arc(x, y, Math.max(0.1, r), 0, Math.PI * 2);
442		ctx.fillStyle = 'rgba(255,255,255,' + Math.max(0, Math.min(1, op)) + ')'; ctx.fill();
443	}
444	function ring(ctx, x, y, r, op){
445		ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2);
446		ctx.strokeStyle = 'rgba(255,255,255,' + op + ')'; ctx.lineWidth = 1; ctx.stroke();
447	}
448
449	hosts.forEach(function(host){
450		var type = host.getAttribute('data-anim');
451		if(!draw[type]){ return; }
452		var canvas = document.createElement('canvas');
453		canvas.width = SIZE * DPR; canvas.height = SIZE * DPR;
454		host.appendChild(canvas);
455		var ctx = canvas.getContext('2d');
456		ctx.scale(DPR, DPR);
457		var t = 0, last = 0;
458		function frame(ts){
459			requestAnimationFrame(frame);
460			if(!last){ last = ts; }
461			t += (ts - last) * 0.001; last = ts;
462			if(!visible){ return; }
463			ctx.clearRect(0, 0, SIZE, SIZE);
464			draw[type](ctx, SIZE / 2, SIZE / 2, t);
465		}
466		requestAnimationFrame(frame);
467	});
468}
469
470/* main-product: 제품 가로 드래그 슬라이더 */
471function main_product_slider(){
472	if(typeof Swiper === 'undefined'){ return; }
473	var el = document.querySelector('.main-product__slider-wrap');
474	if(!el){ return; }
475	var PROD_SET = 5, PROD_JUMP = 20; // 콘텐츠가 5개마다 반복 → 20칸(=4세트) 점프는 픽셀 동일
476	var productSwiper = new Swiper(el, {
477		slidesPerView: 'auto',
478		centeredSlides: true,
479		spaceBetween: '19rem',
480		breakpoints: {
481			541:  { spaceBetween: '20rem' },
482			861:  { spaceBetween: '26rem' },
483			1024: { spaceBetween: '33rem' },
484			1201: { spaceBetween: '37rem' },
485			1481: { spaceBetween: '42rem' }
486		},
487		speed: 500,
488		loop: false,
489		initialSlide: 22,
490		grabCursor: false,
491		slideToClickedSlide: true,
492		autoplay: { delay: 3500, disableOnInteraction: false, pauseOnMouseEnter: true },
493		on: {
494			slideChangeTransitionEnd: function(sw){
495				var ri = sw.activeIndex;
496				if(ri >
496= 33){ sw.slideTo(ri - PROD_JUMP, 0, false); }
497				else if(ri <= 7){ sw.slideTo(ri + PROD_JUMP, 0, false); }
498			}
499		}
500	});
501}
502
503/* 전체메뉴(사이트맵) 열림 시 헤더 .on 을 실제 스크롤 위치(data-scrollpos) 기준으로 유지
504   — nav.js가 body:fixed로 window scrollTop을 0으로 만들어 common.js가 .on을 떼는 것을 보정 */
505function site_map_header_state(){
506	var $header = $('#header');
507	if(!$header.length || !$('#site-map').length || !$('.gnb-full-btn').length){ return; }
508	function sync(){
509		if(!$('#site-map').hasClass('active')){ return; }
510		var sp = parseInt($('body').attr('data-scrollpos') || 0, 10);
511		$header.toggleClass('on', sp >= 100);
512	}
513	$('.gnb-full-btn').on('click', function(){
514		setTimeout(sync, 0);
515		setTimeout(sync, 40);
516	});
517	$(window).on('scroll', sync);
518}
519
520/* 전체메뉴 패널 바깥 클릭 시 닫기 — nav.js 토글 재사용 */
521function site_map_outside_close(){
522	var $sm = $('#site-map');
523	if(!$sm.length){ return; }
524	$(document).on('click', function(e){
525		if(!$sm.hasClass('active')){ return; }
526		var $t = $(e.target);
527		if($t.closest('.site-map-inner').length){ return; }   // 패널 내부는 무시
528		if($t.closest('.gnb-full-btn').length){ return; }      // 토글 버튼은 nav.js가 처리
529		$('.gnb-full-btn.active').first().trigger('click');    // 바깥 → 닫기
530	});
531}
532
533/* 전체메뉴 패널 내 닫기(X) 버튼 → nav.js 토글 재사용 (햄버거와 분리) */
534function site_map_close_btn(){
535	$(document).on('click', '.site-map-close', function(e){
536		e.preventDefault();
537		$('.gnb-full-btn.active').first().trigger('click');
538	});
539}
540
541/* 인사말: 서브비주얼 고정 + 인트로 핀 스크럽(배경 fade-in + 텍스트 up) — movient.kr/mv/greeting wide-visual-next-ele 적응 (860px 초과 전용, 이하는 효과 없이 그냥 스크롤) */
542function greeting_intro_pin(){
543	if(typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined'){ return; }
544	if(!document.body.classList.contains('sub01_01')){ return; }
545	if(window.innerWidth <= 860){ return; }
546	var intro = document.querySelector('.about-page > .greeting-intro');
547	if(!intro){ return; }
548
549	var title = intro.querySelector('.greeting-intro__title');
550
551	ScrollTrigger.create({
552		trigger: intro,
553		start: 'top top',
554		end: '+=100%',
555		scrub: true,
556		pin: true,
557		onUpdate: function(self){
558			var p = self.progress;
559			if(p > 0.1){ intro.classList.add('bg-in'); }
560			else{ intro.classList.remove('bg-in'); }
561			if(p > 0.35){ title.classList.add('active'); }
562			else{ title.classList.remove('active'); }
563		}
564	});
565}
566
567/* 숫자 카운트업: 자리 분할 없이 span 하나의 텍스트를 숫자로 증감 애니메이션 */
568function count_up_number(el, from, to, duration, delay){
569	if(typeof gsap === 'undefined'){ el.textContent = to; return; }
570	var obj = { val: from };
571	gsap.to(obj, {
572		val: to, duration: duration || 0.9, delay: delay || 0, ease: 'power2.out',
573		onUpdate: function(){ el.textContent = Math.round(obj.val); }
574	});
575}
576
577/* 연혁 모바일 연대 구분 헤더: 스크롤 진입 시 0 → 연도 카운트업 (1회) */
578function history_decade_divider_count(){
579	var dividers = document.querySelectorAll('.history-decade-divider');
580	if(!dividers.length){ return; }
581
582	function play(divider){
583		var nums = divider.querySelectorAll('.history-decade-divider__year-num');
584		nums.forEach(function(num, i){
585			var target = parseInt(num.getAttribute('data-target'), 10);
586			if(!target){ return; }
587			count_up_number(num, 0, target, 0.9, i * 0.1);
588		});
589	}
590
591	if(typeof ScrollTrigger !== 'undefined'){
592		dividers.forEach(function(divider){
593			ScrollTrigger.create({ trigger: divider, start: 'top 85%', once: true, onEnter: function(){ play(divider); } });
594		});
595	} else if('IntersectionObserver' in window){
596		var io = new IntersectionObserver(function(entries){
597			entries.forEach(function(entry){
598				if(!entry.isIntersecting){ return; }
599				play(entry.target);
600				io.unobserve(entry.target);
601			});
602		}, { threshold: 0.3 });
603		dividers.forEach(function(divider){ io.observe(divider); });
604	} else {
605		dividers.forEach(play);
606	}
607}
608
609/* history: 스크롤 위치의 연도에 따라 좌측 대형 연대 숫자/라벨 교체 (숫자는 카운트업 효과) */
610function history_decade_motion(){
611	if(typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined'){ return; }
612	var $items = $('.history-timeline .history-item');
613	var $year  = $('.history-decade__year');
614	var $label = $('.history-decade .c-third');
615	if(!$items.length || !$year.length){ return; }
616	var yearEl = $year[0];
617
618	var decades = [
619		{ min:2020, max:2026, start:2020, end:null, label:'혁신 및 미래 도약' },
620		{ min:2010, max:2019, start:2010, end:2019, label:'성장 및 기술 도전' },
621		{ min:1996, max:2009, start:1996, end:2009, label:'설립 및 기반 구축' }
622	];
623
624	var current = null;
625	var prevStart = null;
626	var prevEnd = null;
627
628	function render(d){
629		yearEl.textContent = '';
630
631		var sr = document.createElement('span');
632		sr.className = 'sound_only';
633		sr.textContent = d.start + '~' + (d.end || '');
634		yearEl.appendChild(sr);
635
636		var startEl = document.createElement('span');
637		startEl.className = 'history-decade__year-num';
638		startEl.setAttribute('aria-hidden', 'true');
639		startEl.setAttribute('data-target', d.start);
640		yearEl.appendChild(startEl);
641
642		var sep = document.createElement('span');
643		sep.className = 'history-decade__year-sep';
644		sep.setAttribute('aria-hidden', 'true');
645		sep.textContent = '~';
646		yearEl.appendChild(sep);
647
648		var endEl = null;
649		if(d.end){
650			endEl = document.createElement('span');
651			endEl.className = 'history-decade__year-num';
652			endEl.setAttribute('aria-hidden', 'true');
653			endEl.setAttribute('data-target', d.end);
654			yearEl.appendChild(endEl);
655		}
656
657		count_up_number(startEl, prevStart !== null ? prevStart : 0, d.start, 0.9, 0);
658		if(endEl){ count_up_number(endEl, prevEnd !== null ? prevEnd : 0, d.end, 0.9, 0.1
658); }
659
660		prevStart = d.start;
661		prevEnd = d.end;
662	}
663
664	function setDecade(y){
665		for(var i = 0; i < decades.length; i++){
666			var d = decades[i];
667			if(y >= d.min && y <= d.max){
668				if(current !== i){
669					current = i;
670					$label.text(d.label);
671					render(d);
672				}
673				return;
674			}
675		}
676	}
677
678	$items.each(function(){
679		var y = parseInt($(this).attr('data-year'), 10);
680		if(!y){ return; }
681		ScrollTrigger.create({
682			trigger:this,
683			start:'top center',
684			end:'bottom center',
685			onEnter:function(){ setDecade(y); },
686			onEnterBack:function(){ setDecade(y); }
687		});
688	});
689}
690
691/* history: 상단 대표 사진 — 블러+dim 상태에서 스크롤 진입 시 선명해짐 */
692function history_photo_blur(){
693	if(typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined'){ return; }
694	var imgs = document.querySelectorAll('.js-history-blur img');
695	if(!imgs.length){ return; }
696
697	gsap.matchMedia().add('(min-width:1024px)', function(){
698		var tweens = [];
699		imgs.forEach(function(img){
700			tweens.push(gsap.fromTo(img, { filter:'blur(15px)', opacity:0.5 }, {
701				filter:'blur(0px)', opacity:1, ease:'none',
702				scrollTrigger:{ trigger:img, start:'top bottom', end:'top 40%', scrub:1 }
703			}));
704		});
705
706		return function(){
707			tweens.forEach(function(t){ if(t.scrollTrigger){ t.scrollTrigger.kill(); } t.kill(); });
708			gsap.set(imgs, { clearProps:'filter,opacity' });
709		};
710	});
711}
712
713/* overview-counter: 배경 이미지 스크롤 패럴랙스 (PC/모바일 공통) */
714function overview_counter_parallax(){
715	if(typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined'){ return; }
716	var sec = document.querySelector('.overview-counter');
717	var img = sec && sec.querySelector('.overview-counter__bg img');
718	if(!sec || !img){ return; }
719
720	gsap.fromTo(img, { yPercent: -12 }, {
721		yPercent: 12, ease: 'none',
722		scrollTrigger: { trigger: sec, start: 'top bottom', end: 'bottom top', scrub: true }
723	});
724}
725
726/* 공용 카운터: .js-count 숫자를 0에서 목표값까지 카운트업 (스크롤 진입 1회, 자리 분할 없음) */
727function odometer_count(){
728	var nums = document.querySelectorAll('.js-count');
729	if(!nums.length){ return; }
730
731	function play(el){
732		var target = parseInt((el.getAttribute('data-count') || el.textContent || '').replace(/[^0-9]/g, ''), 10);
733		if(!target){ return; }
734		count_up_number(el, 0, target, 1.2);
735	}
736
737	if('IntersectionObserver' in window){
738		var io = new IntersectionObserver(function(entries){
739			entries.forEach(function(entry){
740				if(!entry.isIntersecting){ return; }
741				play(entry.target);
742				io.unobserve(entry.target);
743			});
744		}, { threshold: 0.4 });
745		nums.forEach(function(el){ io.observe(el); });
746	} else {
747		nums.forEach(play);
748	}
749}
750
751/* overview-cert: 인증서/특허/수상·지정 탭 전환 */
752function overview_cert_tabs(){
753	var tabs = document.querySelectorAll('.overview-cert__tab');
754	var panels = document.querySelectorAll('.overview-cert__panel');
755	if(!tabs.length || !panels.length){ return; }
756	tabs.forEach(function(tab){
757		tab.addEventListener('click', function(){
758			var key = tab.getAttribute('data-tab');
759			tabs.forEach(function(t){ t.classList.toggle('is-active', t === tab); });
760			panels.forEach(function(p){ p.classList.toggle('is-active', p.getAttribute('data-panel') === key); });
761			if(typeof ScrollTrigger !== 'undefined'){ ScrollTrigger.refresh(); }
762		});
763	});
764}
765
766/* location: 주소 클립보드 복사 버튼 */
767function location_copy_address(){
768	var $btn = $('.js-copy-address');
769	if(!$btn.length){ return; }
770	$btn.on('click', function(){
771		var text = $(this).attr('data-copy') || '';
772		if(!text){ return; }
773		if(navigator.clipboard && navigator.clipboard.writeText){
774			navigator.clipboard.writeText(text);
775		} else {
776			var $tmp = $('<textarea readonly></textarea>').val(text).css({position:'fixed', top:'-1000px'}).appendTo('body');
777			$tmp[0].select();
778			document.execCommand('copy');
779			$tmp.remove();
780		}
781	});
782}
783
784/* business-link: nifco rollingActive 적응 — active 1개 자동롤링 + 호버 시 정지, 배경 index 매칭 */
785function business_link_rolling(){
786	var $list = $('.business-link__list');
787	if(!$list.length){ return; }
788	var $items = $list.find('.business-link__item');
789	var itemLength = $items.length;
790	if(itemLength < 2){ return; }
791	var $bgItems = $('.business-link__bg').find('.business-link__bg-item');
792	var rollingSpeed = parseInt($list.attr('data-rolling-time'), 10) || 3000;
793	var startNum = 0;
794	var timer = null;
795	var mq = window.matchMedia('(min-width:1024px)');
796
797	function visualPlay(){
798		$items.each(function(i){
799			$(this).toggleClass('is-active', i === startNum).toggleClass('is-dim', i !== startNum);
800		});
801		$bgItems.each(function(i){
802			$(this).toggleClass('is-active', i === startNum);
803		});
804	}
805	function visualTime(){
806		startNum = (startNum < itemLength - 1) ? startNum + 1 : 0;
807		visualPlay();
808	}
809	function start(){
810		if(timer){ return; }
811		timer = setInterval(visualTime, rollingSpeed);
812	}
813	function stop(){
814		clearInterval(timer);
815		timer = null;
816	}
817	function reset(){
818		stop();
819		$items.removeClass('is-active is-dim');
820		$bgItems.removeClass('is-active').eq(0).addClass('is-active');
821	}
822	function enable(){
823		startNum = 0;
824		visualPlay();
825		start();
826		$items.on('mouseenter.businessLink', function(){
827			stop();
828			startNum = $items.index(this);
829			visualPlay();
830		});
831		$items.on('mouseleave.businessLink', function(){
832			start();
833		});
834	}
835	function disable(){
836		$items.off('.businessLink');
837		reset();
838	}
839	function check(){
840		if(mq.matches){ enable(); } else { disable(); }
841	}
842
843	check();
844	if(mq.addEventListener){ mq.addEventListener('change', check); }
845	else if(mq.addListener){ mq.addListener(check); }
846}
847
848/* process: step 카드 순차 하이라이트 (무한 반복) */
849function process_step_cycle(){
850	var $steps = $('.process__step');
851	if($steps.length < 2){ return; }
852	var idx = $steps.index($steps.filter('.process__step--active'));
853	if(idx < 0){ idx = 0; }
854	setInterval(function(){
855		idx = (idx + 1) % $steps.length;
856		$steps.removeClass('process__step--active').eq(idx).addClass('process__step--active');
857	}, 2800);
858}
859
860/* sub-title h3: 단어 순차 색전환 리빌 (스크롤 진입 1회, 리셋 없음) */
861function sub_title_reveal(){
862	if(typeof SplitText === 'undefined'){ return; }
863	var heads = document.querySelectorAll('h3[data-heading="4xl"]');
864	if(!heads.length){ return; }
865
866	heads.forEach(function(h3){
867		var split = new SplitText(h3, { type: 'lines,words', wordsClass: 'reveal-word', linesClass: 'reveal-line' });
868		var words = split.words;
869
870		function reveal(){
871			words.forEach(function(word, i){
872				setTimeout(function(){ word.classList.add('is-in'); }, i * 120);
873			});
874		}
875
876		if(typeof ScrollTrigger !== 'undefined'){
877			ScrollTrigger.create({ trigger: h3, start: 'top 85%', once: true, onEnter: reveal });
878		} else if('IntersectionObserver' in window){
879			var io = new IntersectionObserver(function(entries){
880				entries.forEach(function(entry){
881					if(!entry.isIntersecting){ return; }
882					reveal();
883					io.unobserve(entry.target);
884				});
885			}, { threshold: 0.3 });
886			io.observe(h3);
887		} else {
888			reveal();
889		}
890	});
891}
892
893/* 대표 이미지: 진입 시 높이 0에서 위아래로 펼쳐짐 (Figma 581:2495) */
894function ceo_img_expand(){
895	var el = document.querySelector('.js-img-expand');
896	if(!el){ return; }
897	function reveal(){ el.classList.add('is-in'); }
898	if(typeof ScrollTrigger !== 'undefined'){
899		ScrollTrigger.create({ trigger: el, start: 'top 80%', once: true, onEnter: reveal });
900	} else if('IntersectionObserver' in window){
901		var io = new IntersectionObserver(function(entries){
902			entries.forEach(function(entry){
903				if(!entry.isIntersecting){ return; }
904				reveal();
905				io.unobserve(entry.target);
906			});
907		}, { threshold: 0.2 });
908		io.observe(el);
909	} else {
910		reveal();
911	}
912}
913
914/* 조직도: 진입 시 부서명 아래 소속부서 셀이 위에서부터 하나씩 떨어지듯 (Figma 581:2445) */
915function greeting_org_cascade(){
916	var list = document.querySelector('.js-org-cascade');
917	if(!list){ return; }
918	var cols = list.querySelectorAll('.greeting-org__col');
919
920	function play(){
921		cols.forEach(function(col){
922			var head = col.querySelector('.greeting-org__head');
923			var cells = col.querySelectorAll('.greeting-org__cells > li');
924			if(head){ head.classList.add('is-in'); }
925			cells.forEach(function(li, i){
926				setTimeout(function(){ li.classList.add('is-in'); }, 150 + i * 110);
927			});
928		});
929	}
930
931	if(typeof ScrollTrigger !== 'undefined'){
932		ScrollTrigger.create({ trigger: list, start: 'top 80%', once: true, onEnter: play });
933	} else if('IntersectionObserver' in window){
934		var io = new IntersectionObserver(function(entries){
935			entries.forEach(function(entry){
936				if(!entry.isIntersecting){ return; }
937				play();
938				io.unobserve(entry.target);
939			});
940		}, { threshold: 0.2 });
941		io.observe(list);
942	} else {
943		play();
944	}
945}
946
947/* 문의 프로세스: 스크롤 진입 시 01→02→03 순차 활성화(무한 반복) */
948function inquery_process_steps(){
949	var $items = $('.cs-form-process__item');
950	if(!$items.length){ return; }
951
952	var idx = -1;
953	var timer = null;
954
955	function step(){
956		idx = (idx + 1) % $items.length;
957		$items.removeClass('is-active').eq(idx).addClass('is-active');
958	}
959
960	function play(){
961		if(timer){ return; }
962		step();
963		timer = setInterval(step, 1800);
964	}
965
966	if(typeof ScrollTrigger !== 'undefined'){
967		ScrollTrigger.create({ trigger: '.cs-form-process', start: 'top 85%', once: true, onEnter: play });
968	} else if('IntersectionObserver' in window){
969		var io = new IntersectionObserver(function(entries){
970			entries.forEach(function(entry){
971				if(!entry.isIntersecting){ return; }
972				play();
973				io.unobserve(entry.target);
974			});
975		}, { threshold: 0.3 });
976		io.observe($items.get(0));
977	} else {
978		play();
979	}
980}
981
982/* product-detail: 썸네일 클릭 시 메인 이미지 교체 */
983function product_detail_gallery(){
984	var $thumbs = $('.product-detail__thumb');
985	var $mainImg = $('[data-main-image]');
986	if(!$thumbs.length || !$mainImg.length){ return; }
987	$thumbs.on('click', function(){
988		var src = $(this).attr('data-thumb-src');
989		if(!src){ return; }
990		$mainImg.attr('src', src);
991		$thumbs.removeClass('is-active');
992		$(this).addClass('is-active');
993	});
994}
995
996/* 제품목록 카테고리 탭 — 가로 스크롤이 생기는 폭에서 활성 탭이 화면 밖에 있으면(예: 마지막 카테고리로 진입)
997   현재 카테고리가 안 보인다. 활성 탭을 가운데로 스크롤해 둔다. 폭이 넉넉하면(스크롤 없음) 아무것도 안 한다. */
998function product_list_tabs_scroll(){
999	var $strip = $('.product-list__tabs');
1000	if(!$strip.length){ return; }
1001
1002	function toActive(){
1003		var strip = $strip.get(0);
1004		var on = strip.querySelector('.is-active');
1005		if(!on){ return; }
1006		if(strip.scrollWidth <= strip.clientWidth + 1){ strip.scrollLeft = 0; return; }
1007		strip.scrollLeft = Math.max(0, on.offsetLeft - (strip.clientWidth - on.offsetWidth) / 2);
1008	}
1009
1010	toActive();
1011	var t;
1012	$(window).on('resize', function(){ clearTimeout(t); t = setTimeout(toActive, 150); });
1013}
1014
1015}); // End jQuery

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.