PageSourceSearch

https://kpc.or.kr/kpc/_js/main.js?var=Sat%20Sep%2026%2003:41:45%20KST%202026

js kpc.or.kr collected 2026-09-25 18:42:00 UTC 32,627 bytes, 979 lines download raw bytes

1$(document).ready(function() { 
2	onMainSlider();
3	
4	$(document).on("click", ".pause", function(){
5		$('.main_silder').slick('slickPause');
6		$('.pause').hide();
7		$('.play').show();
8
9		// 애니메이션 멈춤
10		$('.main_silder').addClass('paused');
11	});	
12
13	$(document).on("click", ".play", function(){
14		$('.main_silder').slick('slickPlay');	
15		$('.play').hide();
16		$('.pause').show();
17
18		// 애니메이션 재시작
19		$('.main_silder').removeClass('paused');
20	});	
21
22});
23
24$(document).ready(function() {
25    //$(".main_silder").on('init', function(event, slick) {
26    //   $(".slider").eq(0).addClass("active-item");
27    //});
28    $(".main_silder").on('afterChange', function(event, slick, currentSlide){
29        $(".slider").removeClass("active-item");
30        $(this).find(".slider").eq(currentSlide).addClass("active-item");
31    });
32    
33    // Slick이 이미 초기화되어 있다면 수동으로 클래스 추가
34    //if ($(".main_silder").hasClass('slick-initialized')) {
35    //    $(".main_silder .slider").eq(0).addClass("active-item");
36    //}
37
38    // Page Visibility API - 탭 전환 감지
39    document.addEventListener('visibilitychange', function() {
40        if (!document.hidden) {
41            // 탭이 다시 활성화되었을 때
42            setTimeout(function() {
43                var $slider = $('.main_silder');
44                
45                if ($slider.length && $slider.hasClass('slick-initialized')) {
46                    var slickInstance = $slider.slick('getSlick');
47                    var currentSlide = slickInstance.currentSlide;
48                    var isPaused = $('.btn-play a').hasClass('paused');
49                    
50                    
51                    if (!isPaused) {
52                        // 현재 슬라이드 정보 가져오기
53                        var $currentSlide = $(slickInstance.$slides[currentSlide]);
54                        var hasVideo = $currentSlide.find('video').length > 0;
55                        var duration = hasVideo ? 10000 : 6000;
56                        
57                        console.log('슬라이더 재시작, duration:', duration);
58                        
59                        // 슬라이더 강제 재시작
60                        $slider.slick('slickPause');
61                        $slider.slick('slickSetOption', 'autoplay', true, false);
62                        $slider.slick('slickSetOption', 'autoplaySpeed', duration, false);
63                        $slider.slick('slickPlay');
64                        
65                        // state_bar 애니메이션 완전 리셋 후 재시작
66                        var $activeBar = $('.main_silder .slick-dots li.slick-active .state_bar');
67                        
68                        // 1. 모든 애니메이션 제거
69                        $('.main_silder .slick-dots .state_bar').css('animation', 'none');
70                        
71                        // 2. 강제 리플로우
72                        $activeBar[0].offsetHeight;
73                        
74                        // 3. 새로운 애니메이션 적용
75                        setTimeout(function() {
76                            var animationStyle = 'progress ' + (duration / 1000 + 0.3) + 's linear forwards';
77                            $activeBar.css({
78                                'animation': animationStyle,
79                                'animation-play-state': 'running'
80                            });
81                        }, 50);
82                    } else {
83                    }
84                }
85            }, 200); // 약간의 지연을 줘서 안정적으로 실행
86        }
87    });
88});
89
90function onMainSlider() {
91	var isPaused = false; // 멈춤 상태 추적 변수
92	
93	$('.main_silder').on('init', function(event, slick){
94		// slick 초기화 후 버튼 추가
95		if(!$('.main_silder .slick-dots .btn-play').length) {
96			$('div.main_silder > ul.slick-dots').append('<li class="btn-play"><a href="javascript:void(0);"><img src="/kpc/_img/main/pause.svg" alt="pause" class="pause"><img src="/kpc/_img/main/play.svg" alt="play" class="play"></a></li>');
97		}
98		
99		// 초기 로드 시 첫 번째 슬라이드 확인 (setTimeout으로 지연)
100		setTimeout(function() {
101			var $firstSlide = $(slick.$slides[0]);
102			var hasVideo = $firstSlide.find('video').length > 0;
103			var duration = hasVideo ? 10000 : 6000;
104			
105			if(hasVideo) {
106				$('.main_silder').slick('slickPause');
107				$('.main_silder').slick('slickSetOption', 'autoplaySpeed', duration, false);
108				$('.main_silder').slick('slickPlay');
109			}
110			
111			// animation duration 설정
112			$('.main_silder .slick-dots li.slick-active .state_bar').css('animation', 'progress ' + (duration / 1000 + 0.3) + 's linear forwards');
113			
114			// 슬라이더 상태 체크 - 주기적으로 paused 상태 확인
115			checkSliderState();
116		}, 100);
117		
118		$(this).on("beforeChange", function(event, slick, currentSlide, nextSlide) {
119			// 다음 슬라이드에 video가 있는지 확인
120			var $nextSlide = $(slick.$slides[nextSlide]);
121			var hasVideo = $nextSlide.find('video').length > 0;
122			var duration = hasVideo ? 10000 : 6000;
123			
124			// 모든 state_bar의 애니메이션 제거
125			$('.main_silder .slick-dots .state_bar').css('animation', 'none');
126			
127			// 강제로 리플로우를 트리거하여 애니메이션 초기화
128			$('.main_silder .slick-dots .state_bar').each(function() {
129				this.offsetHeight;
130			});
131			
132			// 다음 활성화될 state_bar에 새로운 애니메이션 설정
133			setTimeout(function() {
134				var animationStyle = 'progress ' + (duration / 1000 + 0.3) + 's linear forwards';
135				var $nextBar = $('.main_silder .slick-dots li').eq(nextSlide).find('.state_bar');
136				$nextBar.css('animation', animationStyle);
137				
138				// 멈춤 상태였다면 애니메이션도 멈춤
139				if(isPaused) {
140					$nextBar.css('animation-play-state', 'paused');
141				}
142			}, 50);
143		});
144		
145		$(this).on("afterChange", function(event, slick, currentSlide) {
146			$(this).find(".slick-active a").attr("tabindex" , 0);
147			
148			// 현재 슬라이드에 video가 있는지 확인
149			var $currentSlide = $(slick.$slides[currentSlide]);
150			var hasVideo = $currentSlide.find('video').length > 0;
151			var duration = hasVideo ? 10000 : 6000;
152			
153			// 멈춤 상태가 아닐 때만 autoplay 재시작
154			if(!isPaused) {
155				// autoplay 멈추고 옵션 변경 후 다시 시작
156				$(this).slick('slickPause');
157				$(this).slick('slickSetOption', 'autoplaySpeed', duration, false);
158				$(this).slick('slickPlay');
159			}
160			
161		}).on("lazyLoadError", function(event, slick, image, imageSource) {
162			console.log("error");
163		});
164		$(this).addClass("ani");
165	});
166	
167	// 슬라이더 상태를 주기적으로 체크하는 함수
168	function checkSliderState() {
169		setInterval(function() {
170			var $slider = $('.main_silder');
171			if($slider.length && $slider.hasClass('slick-initialized')) {
172				var slickInstance = $slider.slick('getSlick');
173				var isSlickPaused = slickInstance.paused;
174				var $activeBar = $('.main_silder .slick-dots li.slick-active .state_bar');
175				
176				if(isSlickPaused && !isPaused) {
177					// 슬라이더가 멈춰있는데 isPaused는 false인 경우
178					$activeBar.css('animation-play-state', 'paused');
179					isPaused = true;
180					$('.btn-play a').addClass('paused');
181				} else if(!isSlickPaused && isPaused) {
182					// 슬라이더가 재생중인데 isPaused는 true인 경우
183					$activeBar.css('animation-play-state', 'running');
184					isPaused = false;
185					$('.btn-play a').removeClass('paused');
186				}
187			}
188		}, 100); // 100ms마다 체크
189	}
190	
191	$('.main_silder').slick({
192		dots: true,
193		infinite: true,
194		speed: 300,
195		arrows: false,
196		autoplay: true,
197		autoplaySpeed: 6000,
198		fade: true,
199		draggable : true,
200		pauseOnHover:false,
201		pauseOnFocus:false,
202		cssEase: 'cubic-bezier(0.7, 0, 0.3, 1)',
203		customPaging : function(slider, i) {
204			var title = $(slider.$slides[i]).data('title');
205			return '<a href="javascript:void(0);"><div class="percent_circle" active-motion="true"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40px" height="40px" viewBox="0 0 85 85"><circle opacity="0.3" fill="none" enable-background="new" cx="42" cy="42" r="37"></circle><circle opacity="0.4" fill="none" stroke="#FFFFFF" stroke-width="3" stroke-miterlimit="10" cx="42" cy="42" r="37"></circle><circle class="state_bar" fill="none" stroke="var(--Primary)" stroke-width="3" stroke-miterlimit="10" cx="42" cy="42" r="37" style="stroke-dashoffset: 249px; stroke-dasharray: 249;"></circle></svg></div></a>';
206		},
207	});
208}
209
210// 재생/멈춤 버튼 클릭 이벤트 - 함수 밖에서 전역으로 실행
211$(function(){
212	$(document).on('click', '.main_silder .btn-play a', function() {
213		var $slider = $('.main_silder');
214		var $btn = $(this);
215		var $activeBar = $('.main_silder .slick-dots li.slick-active .state_bar');
216		
217		// paused 클래스로 현재 상태 확인 (더 정확함)
218		if($btn.hasClass('paused')) {
219			// 현재 멈춤 상태 -> 재생
220			$slider.slick('slickPlay');
221			$btn.removeClass('paused');
222			
223			// 애니메이션 재개
224			$activeBar.css('animation-play-state', 'running');
225		} else {
226			// 현재 재생 상태 -> 멈춤
227			$slider.slick('slickPause');
228			$btn.addClass('paused');
229			
230			// 애니메이션 멈춤
231			$activeBar.css('animation-play-state', 'paused');
232		}
233	});
234});
235/* ========================================
236숫자 카운트 애니메이션
237======================================== */
238function numberWithCommas(x) {
239 return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
240}
241
242function countUp($el, target) {
243 $({ val: 0 }).animate({ val: target }, {
244     duration: 1200,
245     easing: 'swing',
246     step: function(now) {
247         $el.text(numberWithCommas(Math.floor(now)));
248     },
249     complete: function() {
250         $el.text(numberWithCommas(target));
251     }
252 });
253}
254
255
256
257// 스크롤 이벤트로 카운트 트리거
258$(document).ready(function() {
259	const $slider = $('.main_silder');
260	// 슬라이드가 바뀌고 나서 실행
261	$slider.on('afterChange', function (event, slick, currentSlide) {
262	
263	const $currentSlide = $(slick.$slides[currentSlide]);
264	const $countWrap = $currentSlide.find('.count_wrap');
265	
266	// 현재 슬라이드에 카운트가 없으면 종료
267	if (!$countWrap.length) return;
268	
269	// 이미 카운트 했으면 다시 안 함
270	if ($countWrap.data('counted')) return;
271	
272	$countWrap.data('counted', true);
273	
274	$countWrap.find('.num').each(function () {
275	  const target = parseInt($(this).text().replace(/,/g, ''), 10);
276	      countUp($(this), target);
277	    });
278	  });
279	  
280	  $('.main_silder').on('beforeChange', function (event, slick, currentSlide) {
281	  const $currentSlide = $(slick.$slides[currentSlide]);
282	  const $countWrap = $currentSlide.find('.count_wrap');
283	
284	  if ($countWrap.length) {
285	    $countWrap.data('counted', false);
286	  }
287	});
288});
289
290
291/* 서비스 */
292$(document).ready(function () {
293
294  function updateAllServiceLinks() {
295    $('.m_service .glassList > li').each(function () {
296      var $li = $(this);
297      var $linkWrap = $li.find('.link_wrap');
298      var linkHeight = $li.find('.link').outerHeight();
299
300      $linkWrap.css('height', $li.hasClass('on') ? linkHeight : 0);
301    });
302  }
303
304  // ====== 서비스 hover / focus ======
305  $('.m_service .glassList > li').each(function () {
306    var $li = $(this);
307
308    $li.on('mouseenter focusin', function () {
309      $li.addClass('on');
310      updateAllServiceLinks();
311    }).on('mouseleave focusout', function () {
312      $li.removeClass('on');
313      updateAllServiceLinks();
314    });
315  });
316
317	//사업소개
318	$(window).scroll(function () {
319		if ($(window).scrollTop() > $('.point_fixed_start_before').offset().top) {
320			$('.m_service').addClass("landing_before").removeClass("landing").removeClass("landing_end");
321			isVisible=true;
322		} else {
323			$('.m_service').removeClass("landing_before");
324			isVisible=false;
325		}
326	});
327	$(window).scroll(function () {
328		if ($(window).scrollTop() > $('.point_fixed_start').offset().top) {
329			$('.m_service').addClass("landing").removeClass("landing_before").removeClass("landing_end");
330			isVisible=true;
331		} else {
332			$('.m_service').removeClass("landing");
333			isVisible=false;
334		}
335	});
336	$(window).scroll(function () {
337		if ($(window).scrollTop() > $('.point_fixed_end').offset().top) {
338			$('.m_service').addClass("landing_end").removeClass("landing_before").removeClass("landing");
339			isVisible=true;
340		} else {
341			$('.m_service').removeClass("landing_end");
342			isVisible=false;
343		}
344	});
345//사업소개 목록
346  var $items  = $('.m_service .glassList > li');
347  var $points = $('#pnt_a1, #pnt_a2, #pnt_a3, #pnt_a4');
348
349  // scroll
350  $(window).on('scroll', function () {
351    var scrollTop = $(window).scrollTop();
352    var activeIndex = -1;
353
354    $points.each(function (i) {
355      if (scrollTop > $(this).offset().top) {
356        activeIndex = i;
357      }
358    });
359
360    if (activeIndex !== -1) {
361      $('.m_service')
362        .removeClass('list1 list2 list3 list4')
363        .addClass('list' + (activeIndex + 1));
364
365      $items.removeClass('on')
366        .eq(activeIndex)
367        .addClass('on');
368
369      updateAllServiceLinks();
370
371      $('.main_visual').toggleClass('del', activeIndex === 3);
372    }
373  });
374});
375
376
377$(function () {
378
379    $(".material_sect .cont").each(function () {
380        const $box = $(this);
381        const $tabs = $box.find(".ser_tab a");
382        const $contents = $box.find(".tab_wrap .tab_cont");
383
384        // 초기 상태 (on 클래스 기준)
385        const $activeTab = $tabs.filter(".on");
386
387        $contents.hide();
388        if ($activeTab.length) {
389            $box.find($activeTab.attr("href")).show();
390        }
391
392        // 탭 클릭 이벤트
393        $tabs.on("click", function (e) {
394            e.preventDefault();
395
396            // 탭 on 처리
397            $tabs.removeClass("on");
398            $(this).addClass("on");
399
400            // 콘텐츠 전환
401            $contents.hide();
402            $box.find($(this).attr("href")).show();
403        });
404    });
405
406});
407
408$(document).ready(function() {
409    gsap.registerPlugin(ScrollTrigger);
410    
411    let isCreatingTriggers = false; // 생성 중 플래그
412    let createTimer = null; // 디바운스 타이머
413    
414    // 섹션 활성화 (항상 적용)
415    ScrollTrigger.create({
416        trigger: ".material_sect",
417        start: "top center",
418        end: "bottom center",
419        onEnter: () => $(".material_sect").addClass("active"),
420        onLeave: () => $(".material_sect").removeClass("active"),
421        onEnterBack: () => $(".material_sect").addClass("active"),
422        onLeaveBack: () => $(".material_sect").removeClass("active"),
423        markers: false
424    });
425    
426    const desktopQuery = window.matchMedia('(min-width: 1025px)');
427    
428    function setupDesktopScrollTriggers() {
429        // 이미 생성 중이면 리턴
430        if (isCreatingTriggers) {
431            console.log('이미 생성 중 - 스킵');
432            return;
433        }
434        
435        isCreatingTriggers = true;
436        console.log('=== Desktop ScrollTriggers 설정 시작 ===');
437        
438        const cardBoxes = $(".material_sect .img_cont .cont_box");
439        
440        setTimeout(() => {
441            const isVisible = cardBoxes.first().is(':visible');
442            console.log('cont_box visible:', isVisible);
443            
444            if (!isVisible) {
445                console.warn('cont_box가 아직 보이지 않음 - 재시도');
446                isCreatingTriggers = false;
447                setTimeout(setupDesktopScrollTriggers, 200);
448                return;
449            }
450            
451            const pinStart = 320;
452            const totalCards = cardBoxes.length;
453            const navigationSpans = $(".material_sect .h2_wrap .navigation span");
454            
455            console.log('카드 개수:', totalCards);
456            
457            // h2_wrap 고정
458            ScrollTrigger.create({
459                trigger: ".material_sect .h2_wrap",
460                start: "top 150px",
461                endTrigger: cardBoxes.last()[0],
462                end: "bottom bottom",
463                pin: true,
464                pinSpacing: false,
465                markers: false,
466                id: "h2-pin"
467            });
468            
469            $(".material_sect .h2_wrap").css({'position': 'relative'});
470            
471            // 텍스트 변경 함수
472            function changeH2Text(dataCate, dataTitle) {
473                const $h2Wrap = $(".material_sect .h2_wrap.web");
474                const $currentCate = $h2Wrap.find('.h2_cate');
475                const $currentTitle = $h2Wrap.find('h2');
476                
477                const $oldCate = $currentCate.clone().css({
478                    'position': 'absolute',
479                    'top': $currentCate.position().top,
480                    'left': $currentCate.position().left,
481                    'width': $currentCate.width()
482                }).appendTo($h2Wrap);
483                
484                const $oldTitle = $currentTitle.clone().css({
485                    'position': 'absolute',
486                    'top': $currentTitle.position().top,
487                    'left': $currentTitle.position().left,
488                    'width': $currentTitle.width()
489                }).appendTo($h2Wrap);
490                
491                $currentCate.text(dataCate).css('opacity', 0);
492                $currentTitle.text(dataTitle).css('opacity', 0);
493                
494                gsap.to($oldCate, {
495                    opacity: 0,
496                    duration: 0.5,
497                    onComplete: function() { $oldCate.remove(); }
498                });
499                
500                gsap.to($oldTitle, {
501                    opacity: 0,
502                    duration: 0.5,
503                    onComplete: function() { $oldTitle.remove(); }
504                });
505                
506                gsap.to($currentCate, { opacity: 1, duration: 0.5 });
507                gsap.to($currentTitle, { opacity: 1, duration: 0.5 });
508            }
509            
510            cardBoxes.each(function(i, e) {
511                const isLast = (i === totalCards - 1);
512                const dataCate = $(e).attr('data-cate');
513                const dataTitle = $(e).attr('data-title');
514                const prevCate = i > 0 ? cardBoxes.eq(i - 1).attr('data-cate') : dataCate;
515                const prevTitle = i > 0 ? cardBoxes.eq(i - 1).attr('data-title') : dataTitle;
516                
517                ScrollTrigger.create({
518                    trigger: e,
519                    start: "top center",
520                    end: "top center",
521                    markers: false,
522                    id: `text-change-${i}`,
523                    onEnter: () => changeH2Text(dataCate, dataTitle),
524                    onLeaveBack: () => changeH2Text(prevCate, prevTitle)
525                });
526                
527                ScrollTrigger.create({
528                    trigger: e,
529                    start: `top ${pinStart}px`,
530                    endTrigger: cardBoxes.last()[0],
531                    end: "bottom bottom",
532                    pin: true,
533                    pinSpacing: false,
534                    markers: false,
535                    scrub: 1,
536                    id: `card-pin-${i}`,
537                    onEnter: () => {
538                        cardBoxes.removeClass('autoplay');
539                        navigationSpans.removeClass('on');
540                        cardBoxes.eq(i).addClass('autoplay');
541                        navigationSpans.eq(i).addClass('on');
542                    },
543                    onLeaveBack: () => {
544                        cardBoxes.removeClass('autoplay');
545                        navigationSpans.removeClass('on');
546                        if (i > 0) {
547                            cardBoxes.eq(i - 1).addClass('autoplay');
548                            navigationSpans.eq(i - 1).addClass('on');
549                        }
550                    }
551                });
552                
553                if (!isLast) {
554                    const nextCard = cardBoxes[i + 1];
555                    gsap.to($(e).find(".cont"), {
556                        rotateX: -3,
557                        opacity: 0,
558                        scale: 0.95,
559                        ease: "power2.inOut",
560                        scrollTrigger: {
561                            trigger: nextCard,
562                            start: `top bottom`,
563                            end: `top ${pinStart}px`,
564                            scrub: 1,
565                            markers: false,
566                            id: `card-fade-${i}`
567                        }
568                    });
569                }
570            });
571            
572            console.log('ScrollTrigger 생성 완료');
573            
574            // 강제 새로고침
575            lenis.resize();
576            ScrollTrigger.refresh();
577
578            setTimeout(() => {
579				if (typeof AOS !== 'undefined') {
580					AOS.refresh();
581					console.log('ScrollTrigger 완료 후 AOS 새로고침');
582				}
583			}, 200);
584
585            isCreatingTriggers = false; // 플래그 해제
586            
587			// AOS도 새로고침
588			if (typeof AOS !== 'undefined') {
589				AOS.refresh();
590			}
591
592        }, 300);
593    }
594    
595    function destroyDesktopScrollTriggers() {
596        
597        if (createTimer) {
598            clearTimeout(createTimer);
599            createTimer = null;
600        }
601        
602        ScrollTrigger.getAll().forEach(trigger => {
603            if (trigger.vars.id && (
604                trigger.vars.id.includes('card-') || 
605                trigger.vars.id.includes('text-change-') || 
606                trigger.vars.id === 'h2-pin'
607            )) {
608                trigger.kill();
609            }
610        });
611        
612        isCreatingTriggers = false; // 플래그 해제
613
614		setTimeout(() => {
615			if (typeof AOS !== 'undefined') {
616				AOS.refresh();
617				console.log('ScrollTrigger 제거 후 AOS 새로고침');
618			}
619		}, 200);
620    }
621    
622    function handleBreakpointChange(e) {
623        console.log('브레이크포인트 변경 감지:', e.matches ? 'DESKTOP' : 'MOBILE');
624        
625        // 기존 타이머 취소
626        if (createTimer) {
627            clearTimeout(createTimer);
628        }
629        
630        // 디바운싱: 500ms 후에 실행
631        createTimer = setTimeout(() => {
632            if (e.matches) {
633                // Desktop (1025px 이상)
634                destroyDesktopScrollTriggers();
635                setupDesktopScrollTriggers();
636            } else {
637                // Mobile/Tablet (1024px 이하)
638                destroyDesktopScrollTriggers();
639            }
640
641			setTimeout(() => {
642				if (typeof AOS !== 'undefined') {
643					AOS.refresh();
644					console.log('브레이크포인트 변경 후 AOS 새로고침');
645				}
646			}, 400);
647
648            createTimer = null;
649        }, 500); // 500ms 디바운스
650    }
651    
652    // 초기 실행
653    if (desktopQuery.matches) {
654        setupDesktopScrollTriggers();
655    }
656    
657    // matchMedia 리스너 등록
658    if (desktopQuery.addEventListener) {
659        desktopQuery.addEventListener('change', handleBreakpointChange);
660    } else {
661        // 구형 브라우저 대응
662        desktopQuery.addListener(handleBreakpointChange);
663    }
664});
665
666
667$(document).ready(function() {
668    var serviceSwiper = new Swiper('.material_sect .swiper-container', {
669        loop: true,
670        spaceBetween: 25,
671        effect: 'slide',
672        speed: 1000,
673        autoplay: {
674            delay: 3000,
675            disableOnInteraction: false
676        },
677        slidesPerView: 1,
678        pagination: {
679            el: ".material_sect .swiper-pagination",
680            clickable: true,
681        },
682    });
683    
684    // ===== 각 ser-list별로 독립적인 autoplay 처리 =====
685    $('.ser-list.swiper').each(function() {
686        const $serList = $(this);
687        const $contBox = $serList.closest('.cont_box');
688        const $slides = $serList.find('.swiper-slide');
689        
690        if ($slides.length === 0) return;
691
692        let currentIndex = 0;
693        let autoplayTimer = null;
694        let isHovering = false;
695        let isAutoplayActive = false;
696
697        function setSelected(index) {
698            $slides.removeAttr("selected");
699            $slides.eq(index).attr("selected", "selected");
700            currentIndex = index;
701        }
702
703        function startAutoplay() {
704            if (autoplayTimer || !isAutoplayActive) return;
705            
706            autoplayTimer = setInterval(() => {
707                if (!isHovering) {
708                    currentIndex = (currentIndex + 1) % $slides.length;
709                    setSelected(currentIndex);
710                }
711            }, 2000);
712        }
713
714        function stopAutoplay() {
715            if (autoplayTimer) {
716                clearInterval(autoplayTimer);
717                autoplayTimer = null;
718            }
719        }
720
721        function enableAutoplay() {
722            if (isAutoplayActive) return;
723            
724            isAutoplayActive = true;
725            setSelected(0);
726            startAutoplay();
727        }
728
729        function disableAutoplay() {
730            if (!isAutoplayActive) return;
731            
732            isAutoplayActive = false;
733            stopAutoplay();
734        }
735
736        // 슬라이드 hover 시 selected만 변경, autoplay는 멈추지 않음
737        $slides.on('mouseenter', function() {
738            if (!isAutoplayActive) {
739                $slides.removeAttr("selected");
740                $(this).attr("selected", true);
741                return;
742            }
743            
744            // autoplay 모드일 때는 selected만 변경
745            currentIndex = $slides.index(this);
746            setSelected(currentIndex);
747        });
748
749
750        // a.more에만 autoplay 정지 이벤트
751        $slides.find('a.more').on('mouseenter focus', function() {
752            if (!isAutoplayActive) return;
753            
754            isHovering = true;
755            stopAutoplay();
756            console.log('a.more hover/focus - autoplay 정지');
757        }).on('mouseleave blur', function() {
758            if (!isAutoplayActive) return;
759            
760            isHovering = false;
761            startAutoplay();
762            console.log('a.more leave/blur - autoplay 재개');
763        });
764
765        // ser_tab hover 이벤트
766        $serList.find('.ser_tab').on('mouseenter focus', function() {
767            if (!isAutoplayActive) {
768                $slides.removeAttr("selected");
769                $(this).parent().attr("selected", true);
770                return;
771            }
772            
773            // autoplay 모드일 때는 selected만 변경
774            currentIndex = $slides.index($(this).parent());
775            setSelected(currentIndex);
776            
777            isHovering = true;
778            stopAutoplay();
779            console.log('a.more hover/focus - autoplay 정지');
780        }).on('mouseleave blur', function() {
781            if (!isAutoplayActive) return;
782            
783            isHovering = false;
784            startAutoplay();
785            console.log('a.more leave/blur - autoplay 재개');
786        });
787
788        // MutationObserver로 autoplay 클래스 감지
789        const observer = new MutationObserver((mutations) => {
790            mutations.forEach((mutation) => {
791                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
792                    const hasAutoplay = $contBox.hasClass('autoplay');
793                    
794                    if (hasAutoplay && !isAutoplayActive) {
795                        enableAutoplay();
796                    } else if (!hasAutoplay && isAutoplayActive) {
797                        disableAutoplay();
798                    }
799                }
800            });
801        });
802
803        // 감시 시작
804        if ($contBox.length > 0) {
805            observer.observe($contBox[0], {
806                attributes: true,
807                attributeFilter: ['class']
808            });
809
810            // 초기 상태 확인
811            if ($contBox.hasClass('autoplay')) {
812                enableAutoplay();
813            }
814        }
815    });
816});
817
818/* 테마 */
819$(function () {
820	  const $swiper = $('.theme_swiper');
821	  const $slides = $swiper.find('.swiper-slide');
822	  const delayGap = 300;
823
824	  function resetVisible() {
825	    $slides.removeClass('is-visible');
826	  }
827
828	  function playVisibleAnimation() {
829	    resetVisible();
830
831	    $slides.each(function (i) {
832	      setTimeout(() => {
833	        $(this).addClass('is-visible');
834	      }, i * delayGap);
835	    });
836	  }
837
838	  const observerVisible = new IntersectionObserver((entries) => {
839	    entries.forEach(entry => {
840	      if (entry.isIntersecting) {
841	        playVisibleAnimation();
842	      } else {
843	        resetVisible(); // 다시 진입 시 재생
844	      }
845	    });
846	  }, {
847	    threshold: 0.3
848	  });
849
850	  observerVisible.observe($swiper[0]);
851	});
852
853$(function () {
854	  // 640px 초과 체크 (데스크탑)
855	  const isDesktop = () => window.innerWidth > 640;
856	  
857	  if (!isDesktop()) return; // 모바일이면 종료
858	  
859	  const $swiper = $('.theme_swiper');
860	  const $slides = $swiper.find('.swiper-slide');
861	  const intervalTime = 2000;
862	  const startDelay = 2500; // autoplay 시작 지연 (2.5초)
863	
864	  let currentIndex = 0;
865	  let autoTimer = null;
866	  let delayTimer = null; 
867	  let isHovering = false;
868	  let isInView = false;
869	
870	  function setSelected(index) {
871	    $slides.removeClass("selected").removeAttr("selected");
872	    $slides.eq(index)
873	    .addClass("selected")
874	    .attr("selected", true);
875	  }
876	
877	  function startAutoPlay() {
878	    if (autoTimer || !isInView) return;
879	
880	    autoTimer = setInterval(() => {
881	      if (isHovering) return;
882	
883	      currentIndex = (currentIndex + 1) % $slides.length;
884	      setSelected(currentIndex);
885	    }, intervalTime);
886	  }
887	
888	  function startAutoPlayWithDelay() {
889		  if (delayTimer || !isInView) return;
890		
891		  delayTimer = setTimeout(() => {
892		
893		    // selected 초기화 & 부여
894		    currentIndex = 0;
895		    setSelected(currentIndex);
896		
897		    startAutoPlay();
898		
899		    delayTimer = null;
900		  }, startDelay);
901		}
902	
903	  function stopAutoPlay() {
904	    clearInterval(autoTimer);
905	    autoTimer = null;
906	
907	    clearTimeout(delayTimer);
908	  }
909	
910	  // hover / focus
911	  $slides.on("mouseenter focusin", function () {
912	    isHovering = true;
913	    stopAutoPlay();
914	
915	    currentIndex = $slides.index(this);
916	    setSelected(currentIndex);
917	  });
918	
919	  $slides.on("mouseleave focusout", function () {
920	    isHovering = false;
921	    startAutoPlay();
922	  });
923	
924	  // IntersectionObserver
925	  const observer = new IntersectionObserver((entries) => {
926		  entries.forEach(entry => {
927		    if (entry.isIntersecting) {
928		      isInView = true;
929	
930		      // setSelected 하지 않음
931	  startAutoPlayWithDelay();
932	
933	} else {
934	  isInView = false;
935	  stopAutoPlay();
936	  $slides.removeClass("selected").removeAttr("selected");
937		    }
938		  });
939		}, {
940		  threshold: 0.3
941		});
942	
943	  observer.observe($swiper[0]);
944});
945
946/* 뉴스 커서 */
947$(document).ready(function () {
948  var $preloader = $('.preloader-wrap');
949  var $cursor = $('.cursor');
950
951  var mouseX = 0, mouseY = 0;     // 실제 마우스 위치
952  var cursorX = 0, cursorY = 0;   // 커서의 현재 위치
953
954  // 보간 속도 (값이 작을수록 느리게 따라옴)
955  var speed = 0.1; 
956
957  // mousemove에서 실제 마우스 좌표만 갱신
958  $preloader.on('mousemove', function(e) {
959    var offset = $preloader.offset();
960    mouseX = e.pageX - offset.left;
961    mouseY = e.pageY - offset.top;
962  });
963
964  // requestAnimationFrame으로 부드럽게 위치 갱신
965  function render() {
966    cursorX += (mouseX - cursorX) * speed;
967    cursorY += (mouseY - cursorY) * speed;
968
969    $cursor.css({
970      left: cursorX + 'px',
971      top: cursorY + 'px',
972    });
973
974    requestAnimationFrame(render);
975  }
976
977  render();
978});
979 

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.