PageSourceSearch

https://chest.or.kr/common/v2026/js/ui.common.js?_v=20261002185458

js chest.or.kr collected 2026-10-02 09:57:53 UTC 125,537 bytes, 3,385 lines download raw bytes

1// ui.common.js — 2026 renewal
2
3; (function ($, win, doc, undefined) {
4    'use strict';
5
6    var menuArrayH = GV_ARR_MENU_H_New; // Header Menu Variable
7    var menuArrayF = GV_ARR_MENU_F_New; // Footer Menu Variable
8    // var menuArrayHeaderMo = GV_ARR_MENU_H_MO; // Header Mobile Menu Variable
9
10    $plugins.common = {
11        init: function (opt) {
12            // Header Menu Html !!
13            // $plugins.common.headerMenus();
14            $plugins.common.footerMenus();
15
16            var menuId   = opt.menuId;
17            var menuType = opt.menuType;
18            // console.log(opt)
19
20            // Middle Navigation and Pre/Next Link Setting !!
21            // menuId 가 없으면 menuArrayH or menuArrayF에서 menuId 를 찾는다.
22            var pathName = window.location.pathname;
23
24            if(pathName != "/base.do"){
25                if(gf_isNull(menuId)){
26                    var arrMenuInfo = $plugins.common.findMenuId(pathName, menuType);
27                    // console.log('arrMenuInfo:',arrMenuInfo)
28                    menuId   = arrMenuInfo[0];
29                    menuType = arrMenuInfo[1];
30                }
31            }
32
33            // Header Event Setting !!
34            $plugins.common.header(menuId, menuType);
35
36            // Footer Event Setting : 현제는 구성되어 있지 않음. 후에 필요하면 구현 필요.!!
37            $plugins.common.footer();
38            if(!gf_isNull(menuId)){
39                // 업무페이지인 경우 Body 부분 Class 추가
40                // $("#baseBody").addClass("type-sub");
41
42                // Navigation
43
44                // v2026 breadcrumb (#appBreadcrumb)
45                $plugins.common.breadCrumbs(menuId, menuType);
46                // Middle Previous and Next
47                $plugins.common.middlePreNext(menuId, menuType);
48            }
49            
50//            $.cookie("__branchCd",  opt.branchCd);
51//            $.cookie("__branchId",  opt.branchId);
52//            $.cookie("__branchNm",  opt.branchNm);
53//            $.cookie("__branchUrl", opt.branchUrl);
54//            $.cookie("__menuId",    menuId);
55//            $.cookie("__menuType",  menuType);
56
57            $plugins.uiInputClear();
58            $plugins.uiCaption();
59
60            (!$plugins.browser.mobile) ? $plugins.uiSelect() : '';
61
62            $(win).on('scroll', function () {
63                scrollChange($(win).scrollTop());
64            });
65
66            $plugins.uiHasScrollBar({ selector:$('body') }) ? $('html').addClass('is-scroll') : $('html').removeClass('is-scroll');
67
68            function scrollChange(v) {
69                var win_h = $(win).outerHeight();
70                v > 0
71                    ? $('body').addClass('scrolled')
72                    : $('body').removeClass('scrolled');
73
74                v + win_h + 10 > $(doc).outerHeight()
75                    ? $('body').addClass('scrolled-b')
76                    : $('body').removeClass('scrolled-b');
77
78                v > win_h / 2
79                    ? $('body').addClass('scroll-top')
80                    : $('body').removeClass('scroll-top');
81            }
82            scrollChange($(win).scrollTop());
83            $plugins.common.uiToggleBtn();
84
85            //인증화면에서 휴대폰 번호 , 이름을 클릭 했을 경우에 알림메시지 제공
86            $plugins.common.identity();
87
88            //title 제공
89            $plugins.common.setTitle( opt.branchNm, menuId );
90
91            // '사랑의열매' 메뉴 애니메이션 효과
92            var menucode = menuId.split('_');
93
94            var d1 = Number(menucode[0]);
95            // 메뉴코드가 03일때 애니메이션 실행
96
97            // code가 03일때 애니메이션 실행
98            // 현재 내가 있는 url을 알아와서, 그 url이 포함되어있는 dep2의 객체를 보고 객체의 code가 03이면 실행
99            // 현재 url이 담긴 변수는 newUrl, 객체. 객체를 가져와
100            let ma = menuArrayH.menu;
101            let nowUrl = window.location.href;
102            let urlCut = nowUrl.split('/');
103            // let newUrl = nowUrl.split('/').reverse()[0];
104            let newUrl_dep1 = '/' + urlCut.slice(-2).join('/');
105            let newUrl = '/' + urlCut.slice(-3).join('/'); // 투뎁스 기준
106            // 다른 방법은 없을까?
107            let paramUrl = newUrl.split('?')[0] // 파라미터 제외
108
109            // 현재 url과 link가 맞는지 확인하고 그 link가 포함되어 있는 객체의 code가 03이면 실행
110
111            for(let i=0; i<ma.length; i++) {
112                let dep1Link = ma[i].link;
113
114                if(dep1Link.includes(newUrl_dep1)){
115                    const dep1Menu = document.querySelectorAll('.header__gnb .gnb-list > .gnb-item');
116
117                    // gnb menu 활성화(1뎁스)
118                    dep1Menu.forEach(dep1 => {
119                        const dep1MenuEls = dep1.childNodes;
120                        dep1MenuEls.forEach(el => {
121                            if(el.nodeType === 1 && (el.tagName === 'A' || el.classList.contains('gnb-link'))){ // 엘리먼트 노드인지 확인
122                                const dep1MenuUrl = el.href || '';
123                                if(dep1MenuUrl && dep1MenuUrl.includes(newUrl_dep1)){
124                                    dep1.classList.add('is-active');
125                                }
126                            }
127                        });
128                    });
129                }
130
131                for(let ii=0; ii<ma[i].dep2.length; ii++) {
132                    let dep2Link = ma[i].dep2[ii].link;
133                    let dep2Layout = ma[i].dep2[ii].layout;
134
135                    if(dep2Link.includes(paramUrl)){
136                        // gnb menu 활성화(사랑의열매 2뎁스)
137                        const dep2Menu = document.querySelectorAll('.header__gnb .lnb-list > .lnb-item');
138                        dep2Menu.forEach(dep2 => {
139                            const dep2MenuEls = dep2.childNodes;
140
141                            dep2MenuEls.forEach(el => {
142                                if(el.nodeType === 1 && el.tagName === 'A'){
143                                    const dep2MenuUrl = el.getAttribute('href');
144                                    if(dep2MenuUrl && dep2MenuUrl.includes(paramUrl)){
145                                        dep2.classList.add('is-active');
146                                        const gnbItem = dep2.closest('.gnb-item');
147                                        if (gnbItem) {
148                                            gnbItem.classList.add('is-active');
149                                        }
150                                    }
151                                    // 공지사항 별도처리
152                                    if(paramUrl === '/bbs/1000/initPostList.do' && dep2MenuUrl === '/bbs/1003/initPostList.do'){
153                                        dep2.classList.add('is-active');
154                                        const gnbItem = dep2.closest('.gnb-item');
155                                        if (gnbItem) {
156                                            gnbItem.classList.add('is-active');
157                                        }
158                                    }
159                                }
160                            });
161                        });
162
163                        // 2뎁스 메뉴 페이지일때 1뎁스 활성화
164                        // 해당 페이지의 url이랑 link를 비교, 그 링크가 가지고 있는 code
165                        // 뎁스2 code[0]랑 뎁스1 code[1]이 같으면 dep1에 활성화
166                        let dep1Code = ma[i].code;
167                        let dep1Link = ma[i].link;
168                        let dep1CodeNum = dep1Code.split('_')[0];
169
170                        let dep2Code = ma[i].dep2[ii].code;
171                        let dep2CodeNum = dep2Code.split('_')[0];
172
173                        // dep1 code와 dep2 code 비교(같은 메뉴그룹인지 확인)
174                        // console.log(dep1CodeNum, dep2CodeNum)
175                        if(dep1CodeNum === dep2CodeNum){
176                            const dep1Menus = document.querySelectorAll('.header__gnb .gnb-list > .gnb-item');
177
178                            dep1Menus.forEach(dep1 => {
179                                const dep1MenuEls = dep1.childNodes;
180
181                                dep1MenuEls.forEach(el => {
182                                    if(el.nodeType === 1 && (el.tagName === 'A' || el.classList.contains('gnb-link'))){
183                                        const dep1MenuUrl = el.href || '';
184                                        if(dep1MenuUrl && dep1MenuUrl.includes(dep1Link)){
185                                            el.parentNode.classList.add('is-active');
186                                        }
187                                    }
188                                });
189                            });
190                        }
191                    }
192                }
193            }
194
195        },
196        setTitle : function( branchNm, menuId, pathname ) {
197            let jihoe = "( "+branchNm+" ) 사랑의열매";
198            let title = "";
199
200            let ma = [...menuArrayH.menu, ...menuArrayF.menu];
201            let nowUrl = window.location.href;
202            let urlCut = nowUrl.split('/');
203            let newUrl_dep1 = '/' + urlCut.slice(-2).join('/');
204            let paramUrl = newUrl_dep1.split('?')[0] // 파라미터 제외
205
206            const menuNav = document.querySelector('.menu-nav');
207            
208            const curUrl = pathname || window.location.pathname.split('?')[0];
209
210
211            for (let i = 0; i < ma.length; i++) {
212                const depth1 = ma[i];
213                const dep1 = depth1.name;
214
215                if(depth1.link == curUrl) {
216                    // 서브메인일때
217                    title = depth1.name + " < " ;
218                    break;
219                } else {
220                    // 서브페이지일때
221                    if (depth1.dep2) {
222                        for (let j = 0; j < depth1.dep2.length; j++ ) {
223                            const depth2 = depth1.dep2[j];
224                            if(depth2.link == curUrl) {
225                                title = depth2.name + " < " + dep1 + " < " ;
226                                break;
227                            }
228                        }
229                    }
230                }
231            }
232
233            // 캠페인 별도처리(menuId 세팅되면 재작업하자!)
234            const crwdfund = document.getElementById('crwdfundWrap');
235
236            // 캠페인 페이지 별도 처리
237            if(crwdfund){
238                // menuNav.style.display = 'none';
239                const campaignMenu = menuArrayH.menu.find(function(m){ return m.code && m.code.indexOf('00_') === 0; });
240                const campaignName = (campaignMenu && campaignMenu.name) || '캠페인';
241
242                const title4 = document.getElementById('title4');
243                const titleVal = title4 && title4.value;
244                if(!titleVal){
245                    title = campaignName + " < ";
246                }else{
247                    title = titleVal + " < " + campaignName + " < ";
248                }
249            }
250
251            $("title").text( title + jihoe );
252        },
253        identity : function() {
254            var ids = "#nm , #phone1 , #phone2 , #phone3 , #companyNm , #companyPhone1 , #companyPhone2 , #companyPhone3 , #applcntNm, #ctznPropseNm, #ctznPropsePhone_1, #ctznPropsePhone_2, #ctznPropsePhone_3";
255            $( ids ).off("click").on("click" , function() {
256                alert("휴대폰 번호, 이름 ,생년월일은 인증을 통해 자동입력됩니다.\n오른쪽 인증 버튼을 클릭해주세요.");
257                return false;
258            });
259        },
260        uiToggleBtn: function(){
261            $('.ui-togglebtn .btn-base-imp').attr("title","선택됨");
262            $('.ui-togglebtn button').off('click.tg').on('click.tg', function(){
263                $(this).closest('.ui-togglebtn').find('button').removeClass('btn-base-imp').addClass('btn-base').attr("title","");
264                $(this).removeClass('btn-base').addClass('btn-base-imp').attr("title","선택됨");
265            });
266
267        },
268        header: function (menuId, menuType) {
269            var $nav   = $('#baseNav');
270            var $li_1  = $nav.find('.nav-main-1');
271            var $btn_1 = $nav.find('.nav-btn-1');
272            var timer;
273            var menucode = menuId.split('_');
274
275            $('.ui-menu').on('click', function(){
276                $('.header-mobile').addClass('on');
277            });
278            $('.menu-wrap .btn-close').on('click', function(){
279                $('.header-mobile').removeClass('on');
280            });
281
282            //메뉴 빨간색 강조 다시
283            if(Number(menucode[0]) == "00" || Number(menucode[0]) > 0) {
284                //1depth 강조
285                $li_1.eq(Number(menucode[0])).find('.nav-btn-1').addClass('selected');
286                //2depth 강조
287                var _that = $li_1.eq(Number(menucode[0])).find('.nav-sub > div');
288                $(_that).find('li[_iid="'+menuId+'"]').parent().parent().addClass('selected');
289                //3depth 강조
290                $(_that).find('li[_iid="'+menuId+'"]').find('a').addClass('selected');
291            }
292
293            $btn_1.on('mouseover focus', function(){
294                clearTimeout(timer);
295                $plugins.common.navShow(this);
296            }).on('mouseleave blur', function(){
297                hideTimer();
298            });
299
300            $('.nav-sub, .nav-sub a').on('mouseover focus', function(){
301                clearTimeout(timer);
302            }).on('mouseleave blur', function(){
303                hideTimer();
304            });
305
306            function hideTimer() {
307                timer = setTimeout(function(){
308                    $plugins.common.navHide();
309                },200);
310            }
311
312            $plugins.uiDropdown({
313                id:'uiNavUtil1',
314                ps:'bc',
315                eff:'st'
316            });
317            $plugins.uiDropdown({
318                id:'uiNavUtil2',
319                ps:'bc',
320                eff:'st'
321            });
322            $plugins.uiDropdown({
323                id:'uiNavUtil1_m',
324                ps:'bc',
325                eff:'st'
326            });
327            $plugins.uiDropdown({
328                id:'uiNavUtil2_m',
329                ps:'bc',
330                eff:'st'
331            });
332            $plugins.uiAccordion({
333                id:'AccoNavDepth1',
334                current:null,
335                autoclose:true,
336                callback:function(v){console.log(v)}
337            });
338            $plugins.uiAccordion({
339                id:'AccoNavDepth2-1',
340                current:null,
341                autoclose:true,
342                callback:function(v){console.log(v)}
343            });
344            $plugins.uiAccordion({
345                id:'AccoNavDepth2-2',
346                current:null,
347                autoclose:true,
348                callback:function(v){console.log(v)}
349            });
350            $plugins.uiAccordion({
351                id:'AccoNavDepth2-3',
352                current:null,
353                autoclose:true,
354                callback:function(v){console.log(v)}
355            });
356            $plugins.uiAccordion({
357                id:'AccoNavDepth2-4',
358                current:null,
359                autoclose:true,
360                callback:function(v){console.log(v)}
361            });
362        },
363        navShow: function(t){
364            $(t).closest('.nav-main-1').siblings('li').find('.nav-btn-1').data('selected',false);
365            if (!$(t).data('selected')) {
366                $(t).data('selected', true);
367                $('.nav-main-1').removeClass('on');
368                $('.nav-sub').hide().css({
369                    height: 0,
370                    opacity:0
371                });
372                $(t).closest('.nav-main-1').addClass('on').find('.nav-sub').stop().show().animate({
373                    height: 415,
374                    opacity:1
375                },200);
376
377                $('.dim-nav').addClass('on').stop().animate({
378                    top: 121,
379                    height: 420
380                },150)
381            }
382
383        },
384        navHide: function(){
385            $('.nav-btn-1').data('selected', false);
386            $('.nav-main-1').removeClass('on').find('.nav-sub').stop().hide().animate({
387                height: 0,
388                opacity:0
389            },150);
390            $('.dim-nav').removeClass('on').stop().animate({
391                top: 121,
392                height: 0
393            },200)
394        },
395        footerMenus: function(){
396        },
397        createMenuButton: function(preObj, nextObj, menuType){
398            var preNextHtml = "";
399
400            if(preObj != null){
401                if($(window).innerWidth() <= 1024){
402                    preNextHtml += '<button type="button" data-event="headerMenuClickEvent" data-url="' + preObj.link + '" data-id="' + preObj.code + '" data-type="header_mo" class="prev-menu" title="페이지 이동">' + preObj.name + '</button>';
403                }else{
404                    preNextHtml += '<button type="button" data-event="headerMenuClickEvent" data-url="' + preObj.link + '" data-id="' + preObj.code + '" data-type="' + menuType + '" class="prev-menu" title="페이지 이동">' + preObj.name + '</button>';
405                }
406            }
407
408            if(nextObj != null){
409                if($(window).innerWidth() <= 1024){
410                    preNextHtml += '<button type="button" data-event="headerMenuClickEvent" data-url="' + nextObj.link + '" data-id="' + nextObj.code + '" data-type="' + menuType + '" class="next-menu" title="페이지 이동">' + nextObj.name + '</button>';
411                }else{
412                    preNextHtml += '<button type="button" data-event="headerMenuClickEvent" data-url="' + nextObj.link + '" data-id="' + nextObj.code + '" data-type="' + menuType + '" class="next-menu" title="페이지 이동">' + nextObj.name + '</button>';
413                }
414            }
415            return preNextHtml;
416        },
417        middlePreNext: function(menuId, menuType){
418
419            if($('.contents-menu-nav').length == 0) return;
420
421            // menuType이 header일때 pc버전과 mo버전 구분
422            var ma = menuType == "header" ? menuArrayH.menu : menuArrayF.menu;
423            // var ma_mo = menuType == "header" && window.innerWidth <= 1024 ? menuArrayHeaderMo.menu : undefined;
424
425            if(gf_isNull(menuId)){
426                return false;
427            }
428
429            // code prefix ≠ 배열 index (2026 메뉴는 GNB 순서로 정렬됨)
430            var d1Menu = null;
431            var d2Index = -1;
432            for(var i = 0; i < ma.length; i++) {
433                if(!ma[i].dep2) continue;
434                for(var ii = 0; ii < ma[i].dep2.length; ii++) {
435                    if(ma[i].dep2[ii].code === menuId) {
436                        d1Menu = ma[i];
437                        d2Index = ii;
438                        break;
439                    }
440                }
441                if(d1Menu) break;
442            }
443
444            if(!d1Menu || d2Index < 0) {
445                return false;
446            }
447
448            // 이전, 다음메뉴 생성 변수
449            var preObj  = null;
450            var nextObj = null;
451            var preNextHtml = "";
452
453            if(menuType == "header"){
454                if(d2Index > 0) {
455                    preObj = d1Menu.dep2[d2Index - 1];
456                }
457                if(d1Menu.dep2.length > d2Index + 1) {
458                    nextObj = d1Menu.dep2[d2Index + 1];
459                }
460            }
461
462            if (preObj != null || nextObj != null) {
463                // preObj와 nextObj가 존재할 경우에만 preNextHtml 변수를 초기화하여 버튼 요소를 생성
464                preNextHtml = this.createMenuButton(preObj, nextObj, menuType);
465            }
466
467            var $midMenu = $(".contents-menu-nav");
468
469            if($midMenu.length > 0){
470                $midMenu.html(preNextHtml);
471            }
472
473            // 리사이즈 이벤트 과부하 방지로 디바운스(Debounce) 사용
474            $(window).on('resize', debounce(function() {
475                $plugins.common.middlePreNext(menuId, menuType);
476            }, 100));
477
478            function debounce(func, delay) {
479                var timer;
480                return function() {
481                    var args = arguments;
482                    clearTimeout(timer);
483                    timer = setTimeout(function() {
484                        func.apply(this, args);
485                    }, delay);
486                }
487            }
488        },
489        breadCrumbs: function(menuId, menuType){
490            var $root = $('#appBreadcrumb');
491            if($root.length === 0) return;
492
493            var $itemsWrap = $root.find('.breadcrumb-items');
494            if($itemsWrap.length === 0) return;
495
496            var maNew = (menuType == "footer") ? menuArrayF.menu : menuArrayH.menu;
497            var pathName = window.location.pathname.split('?')[0];
498            var match = $plugins.common.findBreadcrumbMatch(maNew, pathName, menuId);
499
500            if(!match || !match.dep1) {
501                $itemsWrap.empty();
502                return;
503            }
504
505            // 클릭 시 depth2 갱신용으로 메뉴 보관
506            $root.data('bcMenu', maNew);
507            $root.data('bcMatch', match);
508
509            var html = '';
510
511            // depth1: 전체 1depth siblings (클릭 시 이동하지 않고 depth2 갱신)
512            html += $plugins.common.renderBreadcrumbDropdown(
513                match.dep1.name,
514                maNew.map(function(m){
515                    return {
516                        name: m.name,
517                        code: m.code,
518                        active: m.code === match.dep1.code
519                    };
520                }),
521                1
522            );
523
524            // depth2: 현재 1depth의 bc 노출 메뉴
525            var dep2Options = (match.dep1.dep2 || []).filter(function(d){ return d.bc; });
526            if(dep2Options.length) {
527                var dep2Label = (match.dep2 && match.dep2.name) || dep2Options[0].name;
528                html += $plugins.common.renderBreadcrumbDropdown(
529                    dep2Label,
530                    dep2Options.map(function(d){
531                        return {
532                            name: d.name,
533                            link: d.link,
534                            active: match.dep2
535                                ? (d.code === match.dep2.code || d.name === match.dep2.name)
536                                : false,
537                            target: d.target
538                        };
539                    }),
540                    2
541                );
542            }
543
544            $itemsWrap.html(html);
545            $plugins.common.bindBreadcrumbDropdowns($root);
546        },
547
548        findBreadcrumbMatch: function(menuList, pathName, menuId){
549            var dep1 = null;
550            var dep2 = null;
551
552            // 1) path 정확 매칭
553            for(var i = 0; i < menuList.length; i++) {
554                var top = menuList[i];
555                if(!top.dep2) continue;
556                for(var j = 0; j < top.dep2.length; j++) {
557                    if(top.dep2[j].link === pathName) {
558                        return { dep1: top, dep2: top.dep2[j] };
559                    }
560                }
561            }
562
563            // 2) menuId 매칭 (상세·별칭 URL)
564            if(!gf_isNull(menuId)) {
565                for(var i = 0; i < menuList.length; i++) {
566                    var top = menuList[i];
567                    if(top.code === menuId) {
568                        return { dep1: top, dep2: null };
569                    }
570                    if(!top.dep2) continue;
571                    for(var j = 0; j < top.dep2.length; j++) {
572                        if(top.dep2[j].code === menuId) {
573                            dep1 = top;
574                            dep2 = top.dep2[j];
575                            // 동일 이름 bc 대표 항목으로 승격
576                            var named = top.dep2.find(function(d){ return d.bc && d.name === dep2.name; });
577                            return { dep1: dep1, dep2: named || dep2 };
578                        }
579                    }
580                }
581            }
582
583            return null;
584        },
585
586        renderBreadcrumbDropdown: function(label, options, depth){
587            var depthAttr = depth ? ' data-depth="' + depth + '"' : '';
588            var optionsHtml = (options || []).map(function(opt){
589                var cls = opt.active ? ' class="active"' : '';
590                var attrs = '';
591                if(opt.code) attrs += ' data-code="' + opt.code + '"';
592                if(opt.link) attrs += ' data-href="' + opt.link + '"';
593                if(opt.target) attrs += ' data-target="' + opt.target + '"';
594                return '<li' + attrs + cls + '>' + opt.name + '</li>';
595            }).join('');
596
597            return ''
598                + '<div class="breadcrumb-dropdown"' + depthAttr + '>'
599                +   '<button class="breadcrumb-item" type="button">'
600                +     '<span class="breadcrumb-text">' + label + '</span>'
601                +     '<svg class="icon-breadcrumb-chevron" aria-hidden="true">'
602                +       '<use href="/common/v2026/images/icon-sprite.svg#icon-breadcrumb-chevron"></use>'
603                +     '</svg>'
604                +   '</button>'
605                +   '<ul class="breadcrumb-popover">' + optionsHtml + '</ul>'
606                + '</div>';
607        },
608
609        updateBreadcrumbDepth2: function($root, dep1Menu){
610            var $itemsWrap = $root.find('.breadcrumb-items');
611            var $dep2 = $itemsWrap.find('.breadcrumb-dropdown[data-depth="2"]');
612            var dep2Options = (dep1Menu.dep2 || []).filter(function(d){ return d.bc; });
613
614            if(!dep2Options.length) {
615                $dep2.remove();
616                return;
617            }
618
619            var dep2Html = $plugins.common.renderBreadcrumbDropdown(
620                dep2Options[0].name,
621                dep2Options.map(function(d){
622                    return {
623                        name: d.name,
624                        link: d.link,
625                        active: false,
626                        target: d.target
627                    };
628                }),
629                2
630            );
631
632            if($dep2.length) {
633                $dep2.replaceWith(dep2Html);
634            } else {
635                $itemsWrap.append(dep2Html);
636            }
637        },
638
639        bindBreadcrumbDropdowns: function($root){
640            var rootEl = $root.get(0);
641            if(!rootEl || rootEl._bcBound) return;
642            rootEl._bcBound = true;
643
644            $root.on('click.breadcrumb', '.breadcrumb-item', function(e){
645                e.preventDefault();
646                e.stopPropagation();
647                var $wrap = $(this).closest('.breadcrumb-dropdown');
648                var isOpen = $wrap.hasClass('open');
649                $root.find('.breadcrumb-dropdown.open').removeClass('open');
650                if(!isOpen) $wrap.addClass('open');
651            });
652
653            $root.on('click.breadcrumb', '.breadcrumb-popover > li', function(e){
654                e.preventDefault();
655                e.stopPropagation();
656
657                var $li = $(this);
658                var $wrap = $li.closest('.breadcrumb-dropdown');
659                var depth = Number($wrap.attr('data-depth') || 0);
660
661                // depth1: 페이지 이동 없이 depth2 목록 갱신
662                if(depth === 1) {
663                    var code = $li.attr('data-code');
664                    var menuList = $root.data('bcMenu') || [];
665                    var dep1Menu = menuList.find(function(m){ return m.code === code; });
666                    if(!dep1Menu) return;
667
668                    $wrap.find('.breadcrumb-text').text(dep1Menu.name);
669                    $wrap.find('.breadcrumb-popover > li').removeClass('active');
670                    $li.addClass('active');
671                    $wrap.removeClass('open');
672
673                    $plugins.common.updateBreadcrumbDepth2($root, dep1Menu);
674                    return;
675                }
676
677                // depth2(+): 페이지 이동
678                var href = $li.attr('data-href');
679                var target = $li.attr('data-target');
680                if(!href || href === '#') return;
681                if(target === '_blank') {
682                    window.open(href, '_blank');
683                } else {
684                    window.location.href = href;
685                }
686            });
687
688            $(document).on('click.breadcrumb', function(){
689                $root.find('.breadcrumb-dropdown.open').removeClass('open');
690            });
691        },
692        footer: function () {
693
694        },
695        findMenuId: function (pathName, menuType){
696            var arrMenuInfo = new Array(2);
697            // console.log(pathName, menuType)
698            var menuId = "";
699
700            var dep1Bool = true;
701            var dep2Bool = true;
702
703            // menuType이 있으면 바로 분기하여 찾고, 없으면 Header Menu에서 먼저 찾고 없으면 Footer Menu에서 추가로 찾는다.
704            // if(!gf_isNull(menuType)){
705            //     var ma = menuType == "header" ? menuArrayH.menu : menuArrayF.menu;
706            //     console.log(menuType)
707            //     // console.log('여기?')
708            //     for(var i=0; i<ma.length; i++) {
709            //         if(gf_isNull(maH[i].dep2)) continue;
710            //         for (var ii=0; ii<ma[i].dep2.length; ii++) {
711            //             // console.log(maH[i]);
712            //             if(menuType == "header"){
713            //                 var link = maH[i].dep2[ii].link;
714            //                 // console.log(link , pathName);
715            //                 if(link == pathName){
716            //                     menuId = maH[i].dep2[ii].code;
717            //                     dep2Bool = false;
718            //                     break;
719            //                 }
720
721            //                 if(!dep2Bool){
722            //                     dep1Bool = false;
723            //                     break;
724            //                 }
725            //             } else {
726            //                 var link = ma[i].dep2[ii].link;
727
728            //                 if(link == pathName){
729            //                     menuId = ma[i].dep2[ii].code;
730
731            //                     dep1Bool = false;
732            //                     break;
733            //                 }
734            //             }
735            //         }
736
737            //         if(!dep1Bool){
738            //             break;
739            //         }
740            //     }
741            // } else {
742                // Header Menu 에서 찾기
743                var maH = menuArrayH.menu;
744                var maF = menuArrayF.menu;
745                // console.log('menuType:', menuType)
746                for(var i=0; i<maH.length; i++) {
747                    if(gf_isNull(maH[i].dep2)) {
748                        // console.log('dep2가 없으면?')
749                        var link = maH[i].link;
750                        if(link == pathName){
751                            menuId = maH[i].code;
752                            dep1Bool = false;
753                            break;
754                        }
755                    } else {
756                        // console.log('dep2가 있으면?')
757                        var link = maH[i].link;
758                        if(link == pathName){
759                            menuId = maH[i].code;
760                            dep2Bool = false;
761                            var name = maH[i].name;
762                            let menuItems = document.querySelectorAll('.header__gnb .gnb-list > .gnb-item');
763                            for(let j=0; j<menuItems.length; j++){
764                                let menuItem = menuItems[j].querySelector('.gnb-link');
765                                if (menuItem) {  // null 체크 추가
766                                    let menuItemName = menuItem.innerText;
767                                }
768                                    // if(name == menuItemName){
769                                    //     menuItem.parentNode.classList.add('is-active');
770                                    // }
771                            }
772                        }
773                        for (var ii=0; ii<maH[i].dep2.length; ii++) {
774                            var link = maH[i].dep2[ii].link;
775                            if(link == pathName){
776                                menuId = maH[i].dep2[ii].code;
777                                dep2Bool = false;
778                                // break;
779
780                                var name = maH[i].dep2[ii].name;
781                                let menuItems = document.querySelectorAll('.header__gnb .lnb-list > .lnb-item');
782                                for(let j=0; j<menuItems.length; j++){
783                                    let menuItem = menuItems[j].querySelector('a.lnb-link, a');
784                                    if (menuItem) {
785                                        let menuItemName = menuItem.innerText;
786                                    }
787                                        // if(name == menuItemName){
788                                        //     console.log(name)
789                                        //     console.log(menuItem.parentNode)
790                                        //     menuItem.parentNode.classList.add('is-active');
791
792                                        //     // 2뎁스일때 사랑의열매 메뉴 활성화
793                                        //     var menucode = menuId.split('_');
794                                        //     var d1 = Number(menucode[0]);
795                                        //     if(d1 == 3){
796                                        //         const dep2Menu = document.querySelector('.header__gnb');
797                                        //         dep2Menu.classList.add('is-active');
798                                        //     }
799                                        // }
800                                }
801                            }
802                            if(!dep2Bool){
803                                dep1Bool = false;
804                                break;
805                            }
806                        }
807                    }
808                    if(!dep1Bool){
809                        break;
810                    }
811                }
812
813                dep1Bool = true;
814                dep2Bool = true;
815
816                if(!gf_isNull(menuId)){
817                    menuType = "header";
818                } else {
819                    // Header 에 없으면 Footer 에서 찾기
820                    for(var i=0; i<maF.length; i++) {
821                        for (var ii=0; ii<maF[i].dep2.length; ii++) {
822                            var link = maF[i].dep2[ii].link;
823
824                            if(link == pathName){
825                                menuId = maF[i].dep2[ii].code;
826
827                                dep1Bool = false;
828                                break;
829                            }
830                        }
831
832                        if(!dep1Bool){
833                            break;
834                        }
835                    }
836
837                    if(gf_isNull(menuId)){
838                        menuType = "footer";
839                    }
840                }
841            // }
842
843            arrMenuInfo[0] = menuId;
844            arrMenuInfo[1] = menuType;
845
846            return arrMenuInfo;
847        }
848    };
849    //page
850    $plugins.page = {}
851
852    //callback
853    $plugins.callback = {
854        modal: function (modalId) {
855            $plugins.uiInputClear();
856            $plugins.uiCaption();
857            (!$plugins.browser.mobile) ? $plugins.uiSelect() : '';
858
859            switch (modalId) {
860                case 'modalTest2':
861                    break;
862            }
863        }
864    }
865})(jQuery, window, document);
866
867$(function(){
868    $(".contents-hd>h3").attr('title', '선택됨');
869    tabIndex();
870    $(document).on("click", "[data-action]", function(e){
871        tabIndex();
872    });
873    function tabIndex(){
874        $('input[type=text').each(function(){
875            if($(this).is('[readonly]')){
876                $(this).attr('tabindex', '-1')
877            } else{
878                $(this).attr('tabindex', '0')
879            }
880        })
881    }
882
883    $(".ui-acco.type-qna .ui-acco-btn").prepend("<span class='ico-q'>Q</span>");
884    $(".ui-acco.type-qna .ui-acco-pnl").prepend("<span class='ico-a'>A</span>");
885
886    $(window).on('resize', function(){
887        $plugins.common.middlePreNext($plugins.common.menu_id, $plugins.common.menuType);
888    });
889});
890
891// 확인완료
892
893// 사랑의열매 개편용 common.js
894$(function(){
895    checkWindowSize();
896    /*===========================================================
897     * Header Script
898     *===========================================================*/
899    // 헤더 타입은 총 3가지
900    // 1. 헤더에 .dark 클래스가 붙은 타입(.crwdfund-new 클래스가 있을 경우에 헤더에 자동으로 붙음)
901    //   - 크라우드 펀딩 풀버전, 나눔문화활성화 서브메인
902    // 2. 헤더에 .white 클래스가 붙은 타입(.crwdfund-old 클래스가 있을 경우에 헤더에 자동으로 붙음)
903    //   - 크라우드 펀딩 이전 버전
904    // 3. 헤더에 위 두가지가 안붙은 기본 타입 - 나머지 페이지
905    let newHeader = $('.header.type2'); // 개편용 헤더
906    
907    let branchCd = cks.__branchCd || '001';
908    let logoImg = '/common/img/intro/logo';
909
910    if($('.crwdfund-new').length > 0){
911        updateLogo();
912        $(window).resize(function () {
913            updateLogo();
914        });
915        //newHeader.addClass('dark');
916        $('.btn-search').on('click', () => {
917            if(!newHeader.hasClass('on') && newHeader.hasClass('dark')){
918                if(branchCd === '001' || branchCd === '') {
919                    $('.header-inner > h1 > a > img').attr('src', logoImg + '.png');
920                } else {
921                    $('.header-inner > h1 > a > img').attr('src', logoImg + '_' + branchCd + '@2x.png');
922                }
923            } else if(newHeader.hasClass('on')){
924                if(branchCd === '001' || branchCd === '') {
925                    $('.header-inner > h1 > a > img').attr('src', logoImg + '_white.png');
926                } else {
927                    $('.header-inner > h1 > a > img').attr('src', logoImg + '_white' + branchCd + '.png');
928                }
929            }
930        });
931    }
932    else if($('.crwdfund-old').length > 0){
933        newHeader.addClass('white');
934    }
935
936    function updateLogo(){
937        if($(window).width() > 1024){
938            if(branchCd === '001' || branchCd === '') {
939                $('.header-inner > h1 > a > img').attr('src', logoImg + '_white.png');
940            } else {
941                $('.header-inner > h1 > a > img').attr('src', logoImg + '_white' + branchCd + '.png');
942            }
943        } else {
944            if(branchCd === '001' || branchCd === '') {
945                $('.header-inner > h1 > a > img').attr('src', logoImg + '.png');
946            } else {
947                $('.header-inner > h1 > a > img').attr('src', logoImg + '_' + branchCd + '@2x.png');
948            }
949        }
950    }
951
952    // Mobile Header
953    $(document).ready(function () {
954        const $btnGnb = $('.btn-gnb.mo');
955        const $headerMo = $('.header-mo');
956        const $headerInnerMo = $('.header-inner-mo');
957
958        let scrollHandler = null; // 핸들러 저장 변수
959
960        $btnGnb.on('click', function () {
961            const isActive = $headerMo.toggleClass('active').hasClass('active');
962
963            $(this).toggleClass('active');
964            $('.header.type2').css("height", isActive ? "100%" : "");
965            $('html, body').toggleClass('opend', isActive);
966            
967            const $header = $('.header.type2');
968
969            if (isActive) {
970                $header.css({
971                    position: 'fixed',
972                    top: 0,
973                    transform: 'none',
974                    '-webkit-transform': 'none'
975                });
976            }
977
978            toggleScrollLock($headerInnerMo, isActive);
979
980            if (typeof ScrollTrigger !== "undefined") {
981                ScrollTrigger.getAll().forEach(st => {
982                    if (!$(st.trigger).hasClass('video-scroll') && !$(st.trigger).hasClass('image-scroll')) {
983                        isActive ? st.disable() : st.enable();
984                    }
985                });
986
987                ScrollTrigger.refresh();
988
989                if (window.smootherInstance) {
990                    window.smootherInstance.paused(isActive);
991                }
992
993                // 모바일 헤더가 열릴 때 ScrollTrigger의 normalizeScroll 비활성화
994                // Lenis 활성화 시에는 normalizeScroll을 켜지 않음 (wheel 충돌 방지)
995                ScrollTrigger.normalizeScroll(!isActive && !window.__lenis);
996            }
997        });
998
999        // 특정 영역에서만 스크롤 가능하도록 토글하는 함수
1000        function toggleScrollLock($element, enable) {
1001            if (!$element.length) return;
1002
1003            removeScrollLock($element); // 기존 이벤트 제거
1004
1005            if (enable) {
1006                scrollHandler = function (event) {
1007                    const target = event.currentTarget;
1008                    if ((target.scrollTop === 0 && event.deltaY < 0) || 
1009                        (target.scrollTop + target.clientHeight >= target.scrollHeight && event.deltaY > 0)) {
1010                        event.preventDefault();
1011                    }
1012                };
1013
1014                $element.on('wheel touchmove', scrollHandler);
1015            }
1016        }
1017
1018        // 스크롤 제한 해제 함수
1019        function removeScrollLock($element) {
1020            if (scrollHandler) {
1021                $element.off('wheel touchmove', scrollHandler);
1022                scrollHandler = null;
1023            }
1024        }
1025    });
1026
1027
1028    // 이벤트 배너용
1029    $('.btn-gnb.mo').on('click', function(){
1030        $('.btn-gnb.event').addClass('active');
1031    });
1032
1033    $('.btn-gnb.event').on('click', function(){
1034        $(this).removeClass('active');
1035        $('.header.type2').css("height", "");
1036        $('.btn-gnb.mo').removeClass('active');
1037        $('.header-mo').toggleClass('active');
1038        $('html,body').toggleClass('opend');
1039    });
1040    //
1041
1042 // 지회 선택 dropDown
1043    $(function() {
1044
1045        // 드롭다운 닫기
1046        function closeDropdown($btn, $wrap) {
1047            $wrap.removeClass('active');
1048            $btn.removeClass('active').attr('aria-expanded', 'false');
1049            $wrap.find('.region-list a').attr('tabindex', '-1');
1050        }
1051
1052        // 드롭다운 열기
1053        function openDropdown($btn, $wrap) {
1054            $wrap.addClass('active');
1055            $btn.addClass('active').attr('aria-expanded', 'true');
1056            $wrap.find('.region-list a').attr('tabindex', '0');
1057
1058            requestAnimationFrame(function () {
1059                $wrap.find('.region-list a:visible').first().focus();
1060            });
1061        }
1062        
1063        // --- 이벤트 핸들러 ---
1064        // 지회 선택 dropDown (클릭)
1065        $('.btn-region').on('click', function () {
1066            const $btn = $(this);
1067            const $wrap = $btn.next('.region-wrap');
1068            const isOpen = $btn.hasClass('active');
1069            
1070            // 다른 드롭다운 닫기
1071            $('.btn-region').not($btn).removeClass('active').attr('aria-expanded', 'false');
1072            $('.region-wrap').not($wrap).removeClass('active');
1073
1074            if (isOpen) {
1075                closeDropdown($btn, $wrap);
1076            } else {
1077                closeHeaderUtilDropdowns('region');
1078                openDropdown($btn, $wrap);
1079            }
1080        });
1081
1082
1083        // 버튼 키보드
1084        $('.btn-region').on('keydown', function(e) {
1085            var $btn = $(this);
1086            var isOpen = $btn.hasClass('active');
1087
1088            if (e.key === 'Enter' || e.key === ' ') {
1089                e.preventDefault();
1090                // click 핸들러가 open/close 로직을 모두 처리하도록 위임
1091                $btn.click(); 
1092
1093            } else if (e.key === 'ArrowDown' && isOpen) {
1094                e.preventDefault();
1095                // 열려있을 때만 첫 번째 아이템으로 이동
1096                $('.region-list a:visible').first().focus();
1097
1098            } else if (e.key === 'ArrowUp' && isOpen) {
1099                e.preventDefault();
1100                // 열려있을 때만 마지막 아이템으로 이동
1101                $('.region-list a:visible').last().focus();
1102
1103            } else if (e.key === 'Tab') {
1104                // 드롭다운이 열려 있을 때만 Tab 키 가로채기
1105                if (isOpen) { 
1106                    e.preventDefault();
1107                    if (e.shiftKey) {
1108                        $('.region-list a:visible').last().focus();
1109                    } else {
1110                        $('.region-list a:visible').first().focus();
1111                    }
1112                }
1113            } else if (e.key === 'Escape' && isOpen) {
1114                e.preventDefault();
1115                closeDropdown();
1116                $btn.focus(); // 닫은 후 버튼으로 포커스 복귀
1117            }
1118        });
1119
1120        // 메뉴 키보드 (순환)
1121        $('.region-wrap').on('keydown', function(e) {
1122            // 이 핸들러는 내부에 포커스 가능한 요소(tabindex="0"인 <a>)가 있을 때만 활성화됨
1123            var $links = $('.region-list a:visible');
1124            var len = $links.length;
1125            if (len === 0) return; // 보이는 링크가 없으면 중단
1126
1127            var idx = $links.index(document.activeElement);
1128
1129            if (e.key === 'Escape') {
1130                e.preventDefault();
1131                closeDropdown();
1132                $('.btn-region').focus(); // 버튼으로 포커스 복귀
1133
1134            } else if (e.key === 'ArrowDown') {
1135                e.preventDefault();
1136                var nextIdx = (idx === -1) ? 0 : (idx + 1) % len;
1137                $links.eq(nextIdx).focus();
1138
1139            } else if (e.key === 'ArrowUp') {
1140                e.preventDefault();
1141                var prevIdx = (idx <= 0) ? (len - 1) : (idx - 1);
1142                $links.eq(prevIdx).focus();
1143
1144            } else if (e.key === 'Tab') {
1145                e.preventDefault();
1146                if (e.shiftKey) {
1147                    // 첫 번째 링크에서 Shift+Tab → 버튼으로
1148                    if (idx === 0) {
1149                        $('.btn-region').focus();
1150                    } else {
1151                        $links.eq(idx - 1).focus();
1152                    }
1153                } else {
1154                    // 마지막 링크에서 Tab → 버튼으로
1155                    if (idx === len - 1) {
1156                        $('.btn-region').focus();
1157                    } else {
1158                        $links.eq(idx + 1).focus();
1159                    }
1160                }
1161            }
1162        });
1163    });
1164
1165    $('.btn-donate').on('click', function(){
1166        $(this).toggleClass('active');
1167        $(this).siblings('.gnb-donate-wrap').toggleClass('active');
1168        $('.btn-region').removeClass('active');
1169        $('.region-wrap').removeClass('active');
1170
1171        // 웹접근성 작업
1172        if($(this).hasClass('active')){
1173            $(this).appendTo('.donate-wrap');
1174            $('.gnb-donate-wrap ul li > a').attr('tabindex', '0');
1175        }else{
1176            $(this).prependTo('.donate-wrap');
1177            $('.gnb-donate-wrap ul li > a').attr('tabindex', '-1');
1178        }
1179    });
1180
1181    /*===========================================================
1182     * Footer Script
1183     *===========================================================*/
1184    // footer select
1185    $('.btn-footer-select').on('click', function(){
1186        if(!$(this).siblings('.footer-select-wrap').hasClass('on')){
1187            $('.footer-select-wrap').stop().slideUp();
1188            $(this).siblings('.footer-select-wrap').stop().slideDown();
1189
1190            $(this).addClass('on');
1191            $('.footer-select-wrap').removeClass('on');
1192            $(this).siblings('.footer-select-wrap').addClass('on');
1193        }else{
1194            $(this).removeClass('on');
1195            $(this).siblings('.footer-select-wrap').stop().slideUp();
1196            $(this).siblings('.footer-select-wrap').removeClass('on');
1197        }
1198
1199        if($('.select-list.lang').hasClass('active')){
1200            $('.select-list.lang').removeClass('active');
1201            $('.select-list-wrap > button').removeClass('active').attr('aria-expanded', 'false');
1202        }
1203    });
1204
1205    // 언어권 선택
1206    $('.select-list-wrap > button').on('click', function(e){
1207        e.stopPropagation();
1208        var $button = $(this);
1209        var $menu = $button.siblings('ul');
1210        var isOpen = $menu.hasClass('active');
1211
1212        if (isOpen) {
1213            $button.removeClass('active').attr('aria-expanded', 'false');
1214            $menu.removeClass('active');
1215        } else {
1216            closeHeaderUtilDropdowns('lang');
1217            $button.addClass('active').attr('aria-expanded', 'true');
1218            $menu.addClass('active');
1219            $menu.find('a').first().focus();
1220        }
1221    });
1222
1223    // 버튼 키보드
1224    $('.select-list-wrap > button').on('keydown', function(e){
1225        var $button = $(this);
1226        var $menu = $button.siblings('ul');
1227        var isOpen = $menu.hasClass('active');
1228        
1229        if(e.key === 'Enter' || e.key === ' '){
1230            e.preventDefault();
1231            if(isOpen) {
1232                $button.removeClass('active').attr('aria-expanded', 'false');
1233                $menu.removeClass('active');
1234            } else {
1235                $button.click();
1236            }
1237        } else if(e.key === 'ArrowDown' && isOpen){
1238            e.preventDefault();
1239            $menu.find('a').first().focus();
1240        } else if(e.key === 'ArrowUp' && isOpen){
1241            e.preventDefault();
1242            $menu.find('a').last().focus();
1243        } else if(e.key === 'Tab'){
1244            if(isOpen) {
1245                e.preventDefault();
1246                if(e.shiftKey) {
1247                    $menu.find('a').last().focus();
1248                } else {
1249                    $menu.find('a').first().focus();
1250                }
1251            }
1252        } else if(e.key === 'Escape' && isOpen){
1253            e.preventDefault();
1254            $button.removeClass('active').attr('aria-expanded', 'false');
1255            $menu.removeClass('active');
1256        }
1257    });
1258
1259    // 메뉴 키보드 (순환)
1260    $('.select-list-wrap ul').on('keydown', function(e){
1261        var $menu = $(this);
1262        var $button = $menu.siblings('button');
1263        var $links = $menu.find('a');
1264        var idx = $links.index(document.activeElement);
1265        var len = $links.length;
1266        
1267        if(e.key === 'Escape'){
1268            e.preventDefault();
1269            $menu.removeClass('active');
1270            $button.removeClass('active').attr('aria-expanded', 'false').focus();
1271        } else if(e.key === 'ArrowDown'){
1272            e.preventDefault();
1273            $links.eq((idx + 1) % len).focus();
1274        } else if(e.key === 'ArrowUp'){
1275            e.preventDefault();
1276            $links.eq((idx - 1 + len) % len).focus();
1277        } else if(e.key === 'Tab'){
1278            e.preventDefault();
1279            if(e.shiftKey) {
1280                if(idx === 0) {
1281                    $button.focus();
1282                } else {
1283                    $links.eq(idx - 1).focus();
1284                }
1285            } else {
1286                if(idx === len - 1) {
1287                    $button.focus();
1288                } else {
1289                    $links.eq(idx + 1).focus();
1290                }
1291            }
1292        }
1293    });
1294
1295    $(window).on('resize', function() {
1296        checkWindowSize();
1297    });
1298
1299    initLenis2026();
1300    initLegacyScrollTrigger2026();
1301    initLegacyCrwdfundScrollProxy2026();
1302    initJqDatepickerViewportFix2026();
1303    initLegacyModalLock2026(); /* [임시] 레거시 .modal — 리뉴얼 팝업이 footer 동등 구조가 되면 삭제 */
1304    initHonorClubMapTap2026();
1305    initWpeopleOrgChart2026();
1306    initHonorsocietyCckIs2026();
1307    initSrPrivacy2026();
1308    initBhfInfoFilter2026();
1309    initBsnsrsltYAxes2026();
1310    initBsnsrsltWheelScroll2026();
1311    initAosBridge2026();
1312    initHeader2026();
1313    initQuickLink2026();
1314});
1315
1316window.addEventListener('load',()=>{
1317    navCommon();
1318});
1319
1320/* 헤더 util 드롭다운(나의기부내역, 언어, 지회) 닫기 */
1321function closeHeaderUtilDropdowns(except) {
1322    if (except !== 'region') {
1323        var $regionBtn = $('.btn-region.active');
1324        if ($regionBtn.length) {
1325            $regionBtn.removeClass('active').attr('aria-expanded', 'false');
1326            var $regionMenu = $('#region-menu');
1327            $regionMenu.removeClass('active');
1328            $regionMenu.find('.region-list a').attr('tabindex', '-1');
1329        }
1330    }
1331
1332    if (except !== 'lang') {
1333        $('.select-list-wrap > button.active').each(function () {
1334            var $button = $(this);
1335            $button.removeClass('active').attr('aria-expanded', 'false');
1336            $button.siblings('ul').removeClass('active');
1337        });
1338    }
1339
1340    if (except !== 'donation') {
1341        var $donationBtn = $('.header__dropdown--donation .btn.mydonation');
1342        var $donationMenu = $('.header__dropdown--donation .select-list.mydonation');
1343        $donationBtn.removeClass('active').attr('aria-expanded', 'false');
1344        $donationMenu.removeClass('active');
1345    }
1346}
1347
1348/**
1349 * 2026 header — util dropdown, sitemap panel, mobile gnb
1350 */
1351function initHeader2026() {
1352    var $header = $('#baseHeader');
1353    if (!$header.length) return;
1354
1355    var $stmap = $('#stmap');
1356    var $stmapOpen = $header.find('.stmap-open, .header__sitemap--mobile');
1357    var $stmapClose = $stmap.find('.stmap__close');
1358    var $donationBtn = $header.find('.header__dropdown--donation .btn.mydonation');
1359    var $donationMenu = $header.find('.header__dropdown--donation .select-list.mydonation');
1360    var $gnbButton = $header.find('.header__gnb-button');
1361    var $gnbMobile = $header.find('#header-gnb-mobile, .header__gnb-mobile');
1362    var $stmapTrigger = null;
1363    var stmapScrollY = 0;
1364
1365    function getPageScrollY() {
1366        return getLayoutScrollY2026();
1367    }
1368
1369    function restorePageScrollY(y) {
1370        setLayoutScrollY2026(y);
1371    }
1372
1373    function focusStmapTrigger() {
1374        var triggerEl = ($stmapTrigger && $stmapTrigger.length)
1375            ? $stmapTrigger[0]
1376            : $header.find('.stmap-open')[0];
1377        if (triggerEl && triggerEl.focus) {
1378            triggerEl.focus({ preventScroll: true });
1379        }
1380        $stmapTrigger = null;
1381    }
1382
1383    function syncHeaderAfterStmapClose() {
1384        if (typeof window.__syncHeaderScrollState === 'function') {
1385            window.__syncHeaderScrollState();
1386        }
1387    }
1388
1389    function openStmap() {
1390        if (!$stmap.length) return;
1391
1392        stmapScrollY = getPageScrollY();
1393
1394        if (window.__lenis) {
1395            window.__lenis.stop();
1396        }
1397
1398        $stmap.addClass('is-open').attr('aria-hidden', 'false').removeAttr('inert');
1399        $stmapOpen.attr('aria-expanded', 'true');
1400        $('body').addClass('is-stmap-open');
1401
1402        // overflow:hidden 적용 시 스크롤 위치가 초기화되는 브라우저 대비
1403        restorePageScrollY(stmapScrollY);
1404
1405        var stmapEl = $stmap[0];
1406        var closeBtn = $stmapClose[0];
1407
1408        function resetScrollAndFocus() {
1409            stmapEl.scrollTop = 0;
1410            if (closeBtn && closeBtn.focus) {
1411                closeBtn.focus({ preventScroll: true });
1412            }
1413        }
1414
1415        function onTransitionEnd(e) {
1416            if (e.target !== stmapEl || e.propertyName !== 'height') {
1417                return;
1418            }
1419            clearTimeout(fallbackTimer);
1420            stmapEl.removeEventListener('transitionend', onTransitionEnd);
1421            resetScrollAndFocus();
1422        }
1423
1424        stmapEl.addEventListener('transitionend', onTransitionEnd);
1425
1426        var fallbackTimer = setTimeout(function () {
1427            stmapEl.removeEventListener('transitionend', onTransitionEnd);
1428            resetScrollAndFocus();
1429        }, 350);
1430
1431        requestAnimationFrame(function () {
1432            var duration = parseFloat(window.getComputedStyle(stmapEl).transitionDuration) || 0;
1433            if (duration === 0) {
1434                clearTimeout(fallbackTimer);
1435                stmapEl.removeEventListener('transitionend', onTransitionEnd);
1436                resetScrollAndFocus();
1437            }
1438        });
1439    }
1440
1441    function closeStmap() {
1442        if (!$stmap.length) return;
1443        $stmap.removeClass('is-open').attr('aria-hidden', 'true').attr('inert', '');
1444        $stmapOpen.attr('aria-expanded', 'false');
1445        $('body').removeClass('is-stmap-open');
1446        $stmap[0].scrollTop = 0;
1447
1448        restorePageScrollY(stmapScrollY);
1449
1450        if (window.__lenis && !$gnbMobile.hasClass('is-open')) {
1451            window.__lenis.start();
1452            restorePageScrollY(stmapScrollY);
1453        }
1454
1455        focusStmapTrigger();
1456        syncHeaderAfterStmapClose();
1457    }
1458
1459    function openGnbMobile() {
1460        if (!$gnbMobile.length) return;
1461
1462        closeHeaderUtilDropdowns();
1463        closeStmapQuiet();
1464
1465        $gnbMobile.addClass('is-open');
1466        $header.addClass('is-gnb-open');
1467        $('body').addClass('is-gnb-open');
1468        $gnbButton.attr('aria-expanded', 'true').attr('aria-label', '메뉴 닫기');
1469
1470        resetMoGnbPanels();
1471        var $first = $gnbMobile.find('.mo-gnb-item-level1').first();
1472        $first.addClass('is-active')
1473            .children('.label')
1474            .attr('aria-expanded', 'true');
1475
1476        if (window.__lenis) {
1477            window.__lenis.stop();
1478        }
1479    }
1480
1481    function closeGnbMobile() {
1482        if (!$gnbMobile.length) return;
1483
1484        closeHeaderUtilDropdowns();
1485
1486        $gnbMobile.removeClass('is-open');
1487        $header.removeClass('is-gnb-open');
1488        $('body').removeClass('is-gnb-open');
1489        $gnbButton.attr('aria-expanded', 'false').attr('aria-label', '메뉴 열기');
1490
1491        resetMoGnbPanels();
1492
1493        if (window.__lenis && !$stmap.hasClass('is-open')) {
1494            window.__lenis.start();
1495        }
1496    }
1497
1498    function resetMoGnbPanels() {
1499        $gnbMobile.find('.mo-gnb-item-level1.is-active, .mo-gnb-item-level2.is-active')
1500            .removeClass('is-active');
1501        $gnbMobile.find('.mo-gnb-item-level1 > .label[aria-expanded="true"], .mo-gnb-toggle[aria-expanded="true"]')
1502            .attr('aria-expanded', 'false');
1503    }
1504
1505    function closeStmapQuiet() {
1506        if (!$stmap.length || !$stmap.hasClass('is-open')) return;
1507        $stmap.removeClass('is-open').attr('aria-hidden', 'true').attr('inert', '');
1508        $stmapOpen.attr('aria-expanded', 'false');
1509        $('body').removeClass('is-stmap-open');
1510        $stmap[0].scrollTop = 0;
1511        $stmapTrigger = null;
1512        restorePageScrollY(stmapScrollY);
1513        syncHeaderAfterStmapClose();
1514    }
1515
1516    function closeDonationMenu() {
1517        $donationBtn.removeClass('active').attr('aria-expanded', 'false');
1518        $donationMenu.removeClass('active');
1519    }
1520
1521    $stmapOpen.on('click', function (e) {
1522        e.preventDefault();
1523        $stmapTrigger = $(this);
1524        openStmap();
1525    });
1526
1527    $stmapClose.on('click', function (e) {
1528        e.preventDefault();
1529        closeStmap();
1530    });
1531
1532    $gnbButton.on('click', function (e) {
1533        e.preventDefault();
1534        if ($gnbMobile.hasClass('is-open')) {
1535            closeGnbMobile();
1536        } else {
1537            openGnbMobile();
1538        }
1539    });
1540
1541    /* 데스크톱 GNB 1뎁스: 마우스로는 포커스 주지 않음 (키보드 focus-within 유지) */
1542    $header.on('mousedown', '.header__gnb .gnb-link', function (e) {
1543        if (window.innerWidth <= 1024) return;
1544        if (e.button !== 0) return;
1545        e.preventDefault();
1546    });
1547
1548    /* 다른 gnb-item 진입 시 이전 메뉴에 남은 포커스 제거 → 패널 중복 노출 방지 */
1549    $header.on('mouseenter', '.header__gnb .gnb-item', function () {
1550        if (window.innerWidth <= 1024) return;
1551        $header.find('.header__gnb .gnb-item').not(this).each(function () {
1552            var focused = this.querySelector(':focus');
1553            if (focused) focused.blur();
1554        });
1555    });
1556
1557    /* 데스크톱 GNB: 새창 링크 클릭 시 2차 패널 닫기 (:hover/:focus-within 잔존 방지) */
1558    $header.on('click', '.header__gnb .gnb-panel a[target="_blank"]', function () {
1559        if (window.innerWidth <= 1024) return;
1560        var $item = $(this).closest('.gnb-item');
1561        this.blur();
1562        $item.addClass('is-panel-closed');
1563    });
1564
1565    $header.on('mouseleave', '.header__gnb .gnb-item', function () {
1566        $(this).removeClass('is-panel-closed');
1567    });
1568
1569
1570    /* 1뎁스: 왼쪽 탭 — 항상 하나 선택(시안과 동일) */
1571    $gnbMobile.on('click', '.mo-gnb-item-level1 > .label', function (e) {
1572        e.preventDefault();
1573        var $item = $(this).closest('.mo-gnb-item-level1');
1574
1575        $gnbMobile.find('.mo-gnb-item-level1.is-active')
1576            .not($item)
1577            .removeClass('is-active')
1578            .children('.label')
1579            .attr('aria-expanded', 'false');
1580        $gnbMobile.find('.mo-gnb-item-level2.is-active')
1581            .removeClass('is-active')
1582            .find('.mo-gnb-toggle')
1583            .attr('aria-expanded', 'false');
1584
1585        $item.addClass('is-active');
1586        $(this).attr('aria-expanded', 'true');
1587    });
1588
1589    /* 2뎁스: 하위(3뎁스)가 있으면 오른쪽 패널 내 아코디언 */
1590    $gnbMobile.on('click', '.mo-gnb-toggle', function (e) {
1591        e.preventDefault();
1592        var $btn = $(this);
1593        var $item = $btn.closest('.mo-gnb-item-level2');
1594        var isActive = $item.hasClass('is-active');
1595
1596        $gnbMobile.find('.mo-gnb-item-level2.is-active')
1597            .not($item)
1598            .removeClass('is-active')
1599            .find('.mo-gnb-toggle')
1600            .attr('aria-expanded', 'false');
1601
1602        if (isActive) {
1603            $item.removeClass('is-active');
1604            $btn.attr('aria-expanded', 'false');
1605        } else {
1606            $item.addClass('is-active');
1607            $btn.attr('aria-expanded', 'true');
1608        }
1609    });
1610
1611    $(document).on('keydown.header2026Stmap', function (e) {
1612        if (e.key !== 'Escape') return;
1613
1614        if ($stmap.hasClass('is-open')) {
1615            e.preventDefault();
1616            closeStmap();
1617            return;
1618        }
1619
1620        if ($gnbMobile.hasClass('is-open')) {
1621            e.preventDefault();
1622            closeGnbMobile();
1623            $gnbButton.trigger('focus');
1624        }
1625    });
1626
1627    $(window).on('resize.header2026Gnb', function () {
1628        if (window.innerWidth >= 1024 && $gnbMobile.hasClass('is-open')) {
1629            closeGnbMobile();
1630        }
1631    });
1632
1633    $donationBtn.on('click', function (e) {
1634        e.preventDefault();
1635        e.stopPropagation();
1636        var $btn = $(this);
1637        var isOpen = $donationMenu.hasClass('active');
1638
1639        if (isOpen) {
1640            closeDonationMenu();
1641        } else {
1642            closeHeaderUtilDropdowns('donation');
1643            $btn.addClass('active').attr('aria-expanded', 'true');
1644            $donationMenu.addClass('active');
1645        }
1646    });
1647
1648    $(document).on('click.header2026Donation', function (e) {
1649        if (!$(e.target).closest('.header__dropdown--donation').length) {
1650            closeDonationMenu();
1651        }
1652    });
1653}
1654
1655/**
1656 * overflow-y 스크롤 영역 — Lenis wheel 가로채기 예외 처리
1657 * 기본 범위: #baseBody + #baseHeader (지회 드롭다운 등)
1658 * @param {Document|Element} [scope]
1659 */
1660function applyLenisPreventToNestedScroll2026(scope) {
1661    if (!window.__lenis) {
1662        return;
1663    }
1664
1665    var roots = scope
1666        ? [scope]
1667        : [document.getElementById('baseBody'), document.getElementById('baseHeader')];
1668
1669    for (var r = 0; r < roots.length; r++) {
1670        var root = roots[r];
1671        if (!root || !root.querySelectorAll) {
1672            continue;
1673        }
1674
1675        var nodes = root.querySelectorAll('*');
1676        for (var i = 0; i < nodes.length; i++) {
1677            var el = nodes[i];
1678            if (el.id === 'baseWrap' || el.id === 'baseWrapContent') {
1679                continue;
1680            }
1681            if (el.hasAttribute('data-lenis-prevent')) {
1682                continue;
1683            }
1684
1685            var style = window.getComputedStyle(el);
1686            var overflowY = style.overflowY;
1687            if (overflowY !== 'auto' && overflowY !== 'scroll') {
1688                continue;
1689            }
1690
1691            // overflow-x:auto 만 있는 영역(세로 스크롤 없음)은 Lenis 예외 대상에서 제외
1692            // — overflow-x:auto 시 overflow-y가 auto로 계산되어 canvas-inner 등이 오탐됨
1693            if (el.scrollHeight <= el.clientHeight + 1) {
1694                var overflowX = style.overflowX;
1695                if (overflowX === 'auto' || overflowX === 'scroll') {
1696                    continue;
1697                }
1698            }
1699
1700            el.setAttribute('data-lenis-prevent', '');
1701        }
1702
1703        // textarea — computed overflow-y가 auto/scroll이 아니어도 내부 스크롤 가능 (약관 등)
1704        var textareas = root.querySelectorAll('textarea');
1705        for (var t = 0; t < textareas.length; t++) {
1706            var ta = textareas[t];
1707            if (ta.hasAttribute('data-lenis-prevent')) {
1708                continue;
1709            }
1710            if (ta.scrollHeight > ta.clientHeight + 1) {
1711                ta.setAttribute('data-lenis-prevent', '');
1712            }
1713        }
1714    }
1715}
1716window.applyLenisPreventToNestedScroll2026 = applyLenisPreventToNestedScroll2026;
1717
1718/**
1719 * Lenis 활성 페이지 — 탭 전환·로드 후 중첩 스크롤 영역 재스캔
1720 * (숨겨진 ui-tab-pnl 안 textarea는 초기 스캔에서 scrollHeight 측정이 부정확할 수 있음)
1721 */
1722function initLenisNestedScrollTabRescan2026() {
1723    if (window.__lenisNestedScrollTabRescanBound) {
1724        return;
1725    }
1726    window.__lenisNestedScrollTabRescanBound = true;
1727
1728    function scheduleRescan() {
1729        requestAnimationFrame(function () {
1730            applyLenisPreventToNestedScroll2026();
1731        });
1732    }
1733
1734    $(document).on('click.lenisNestedScroll', '.ui-tab-btn', scheduleRescan);
1735    window.addEventListener('load', scheduleRescan);
1736
1737    if (window.$plugins && typeof $plugins.uiTabAct === 'function' && !$plugins.uiTabAct.__lenisPatched2026) {
1738        var originalUiTabAct = $plugins.uiTabAct;
1739        $plugins.uiTabAct = function (opt) {
1740            var result = originalUiTabAct.apply(this, arguments);
1741            scheduleRescan();
1742            return result;
1743        };
1744        $plugins.uiTabAct.__lenisPatched2026 = true;
1745    }
1746}
1747
1748/**
1749 * Lenis(#baseWrap) ↔ GSAP ScrollTrigger 연동
1750 * - 레거시 suprt-sub 등 window 스크roller 기준 ScrollTrigger를 v2026 스크롤 루트에 맞춤
1751 * - ScrollSmoother 사용 페이지는 제외
1752 */
1753function initScrollTriggerLenisBridge2026() {
1754    if (!window.__lenis || typeof ScrollTrigger === 'undefined') {
1755        return;
1756    }
1757
1758    if (typeof ScrollSmoother !== 'undefined' && ScrollSmoother.get && ScrollSmoother.get()) {
1759        return;
1760    }
1761
1762    var wrapper = document.getElementById('baseWrap');
1763    if (!wrapper) {
1764        return;
1765    }
1766
1767    if (!window.__lenisScrollTriggerBridge) {
1768        window.__lenisScrollTriggerBridge = true;
1769
1770        ScrollTrigger.scrollerProxy(wrapper, {
1771            scrollTop: function (value) {
1772                if (arguments.length) {
1773                    window.__lenis.scrollTo(value, { immediate: true });
1774                }
1775                return window.__lenis.scroll;
1776            },
1777            getBoundingClientRect: function () {
1778                return {
1779                    top: 0,
1780                    left: 0,
1781                    width: wrapper.clientWidth,
1782                    height: wrapper.clientHeight
1783                };
1784            },
1785            pinType: wrapper.style.transform ? 'transform' : 'fixed'
1786        });
1787
1788        window.__lenis.on('scroll', ScrollTrigger.update);
1789
1790        ScrollTrigger.defaults({
1791            scroller: wrapper
1792        });
1793
1794        ScrollTrigger.normalizeScroll(false);
1795
1796        if (!window.__lenisScrollTriggerLoadBound) {
1797            window.__lenisScrollTriggerLoadBound = true;
1798            window.addEventListener('load', function () {
1799                initScrollTriggerLenisBridge2026();
1800            });
1801        }
1802    }
1803
1804    ScrollTrigger.refresh();
1805}
1806window.initScrollTriggerLenisBridge2026 = initScrollTriggerLenisBridge2026;
1807
1808/**
1809 * 아너 소사이어티 클럽 지도 — 모바일에서 area mouseout 이 말풍선을 바로 지워
1810 * 상세보기를 누를 수 없음. JSP는 수정하지 않고 capture 단계에서 mouseout 을 막는다.
1811 * (상세보기 노출 기준과 맞춤: max-width 1080px)
1812 */
1813function initHonorClubMapTap2026() {
1814    var mapInner = document.querySelector('.honor-new .club-map-inner');
1815    if (!mapInner) {
1816        return;
1817    }
1818
1819    var mq = window.matchMedia('(max-width: 1080px)');
1820
1821    mapInner.addEventListener('mouseout', function (e) {
1822        if (!mq.matches) {
1823            return;
1824        }
1825        if (e.target && e.target.tagName === 'AREA') {
1826            e.stopPropagation();
1827        }
1828    }, true);
1829}
1830
1831/* =============================================================================
1832 * [임시] 사업성과 차트 — yAxes를 본차트 canvas에 고정
1833 * -----------------------------------------------------------------------------
1834 * 막대 차트는 1200px 고정 + canvas-inner overflow-x:auto.
1835 * 가로 스크롤바가 생기면 wrap 높이가 늘어나 yAxes(bottom:18px)만 내려가
1836 * 회색 선·왼쪽 눈금이 막대와 어긋난다. 스크롤바 높이가 아닌 본차트
1837 * getBoundingClientRect에 붙여 정렬한다.
1838 * 삭제 조건: 사업성과 JSP를 2026 마크업으로 전환 완료 시
1839 * ============================================================================= */
1840var BSNSRSLT_YAXES_GAP_2026 = 18;
1841
1842function syncBsnsrsltYAxes2026() {
1843    var wraps = document.querySelectorAll('.cck-sub .chart-wrap .canvas-wrap');
1844    if (!wraps.length) {
1845        return;
1846    }
1847
1848    wraps.forEach(function (wrap) {
1849        var inner = wrap.querySelector('.canvas-inner');
1850        var chartCanvas = inner && inner.querySelector('canvas');
1851        var yAxes = wrap.querySelector('.yAxes');
1852        if (!chartCanvas || !yAxes) {
1853            return;
1854        }
1855
1856        var wrapRect = wrap.getBoundingClientRect();
1857        var chartRect = chartCanvas.getBoundingClientRect();
1858        var yAxesH = yAxes.getBoundingClientRect().height;
1859        if (!yAxesH) {
1860            return;
1861        }
1862
1863        var top = chartRect.bottom - wrapRect.top - yAxesH - BSNSRSLT_YAXES_GAP_2026;
1864        yAxes.style.top = Math.round(top) + 'px';
1865        yAxes.style.bottom = 'auto';
1866    });
1867}
1868
1869function initBsnsrsltYAxes2026() {
1870    var wraps = document.querySelectorAll('.cck-sub .chart-wrap .canvas-wrap');
1871    if (!wraps.length) {
1872        return;
1873    }
1874
1875    syncBsnsrsltYAxes2026();
1876    window.addEventListener('load', syncBsnsrsltYAxes2026);
1877    window.addEventListener('resize', syncBsnsrsltYAxes2026);
1878
1879    if (typeof ResizeObserver === 'function') {
1880        var ro = new ResizeObserver(function () {
1881            syncBsnsrsltYAxes2026();
1882        });
1883        wraps.forEach(function (wrap) {
1884            var inner = wrap.querySelector('.canvas-inner');
1885            if (inner) {
1886                ro.observe(inner);
1887            }
1888        });
1889    }
1890
1891    document.addEventListener('click', function (e) {
1892        var tabBtn = e.target.closest && e.target.closest('.cck-sub .chart-wrap .btn-tab, .cck-sub .chart-wrap .select-btn');
1893        if (!tabBtn) {
1894            return;
1895        }
1896        setTimeout(syncBsnsrsltYAxes2026, 0);
1897    });
1898}
1899
1900/* =============================================================================
1901 * [임시] 사업성과 — 가로 overflow 영역 마우스 휠 스크롤
1902 * -----------------------------------------------------------------------------
1903 * canvas-inner(차트), wide-scroll(표)에 실제 가로 스크롤이 있을 때만
1904 * 세로 휠을 가로 스크롤로 변환하고 Lenis 휠을 예외 처리한다.
1905 * 가로 overflow가 없으면 Lenis 예외 attribute를 제거해 페이지 세로 스크롤을 유지한다.
1906 * 삭제 조건: 사업성과 JSP를 2026 마크업으로 전환 완료 시
1907 * ============================================================================= */
1908var bsnsrsltWheelScrollBound2026 = false;
1909
1910function applyBsnsrsltWheelScrollLenisPrevent2026() {
1911    document.querySelectorAll('.cck-sub .canvas-inner, .cck-sub .table-wrap .wide-scroll').forEach(function (el) {
1912        if (el.scrollWidth > el.clientWidth) {
1913            el.setAttribute('data-lenis-prevent-wheel', '');
1914        } else {
1915            el.removeAttribute('data-lenis-prevent-wheel');
1916            el.removeAttribute('data-lenis-prevent');
1917        }
1918    });
1919}
1920
1921function onBsnsrsltWheelScroll2026(e) {
1922    var el = e.target.closest && e.target.closest('.cck-sub .canvas-inner, .cck-sub .table-wrap .wide-scroll');
1923    if (!el || el.scrollWidth <= el.clientWidth) {
1924        return;
1925    }
1926
1927    var delta = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.deltaY;
1928    if (!delta) {
1929        return;
1930    }
1931
1932    var maxScroll = el.scrollWidth - el.clientWidth;
1933    var atStart = el.scrollLeft <= 0;
1934    var atEnd = el.scrollLeft >= maxScroll - 1;
1935
1936    if ((delta < 0 && !atStart) || (delta > 0 && !atEnd)) {
1937        e.preventDefault();
1938        el.scrollLeft = Math.max(0, Math.min(maxScroll, el.scrollLeft + delta));
1939    }
1940}
1941
1942function initBsnsrsltWheelScroll2026() {
1943    if (!/\/lf\/intrcn\/initBsnsrslt\.do/.test(window.location.pathname)) {
1944        return;
1945    }
1946    if (!document.querySelector('.cck-sub')) {
1947        return;
1948    }
1949
1950    applyBsnsrsltWheelScrollLenisPrevent2026();
1951
1952    if (!bsnsrsltWheelScrollBound2026) {
1953        bsnsrsltWheelScrollBound2026 = true;
1954        document.addEventListener('wheel', onBsnsrsltWheelScroll2026, { passive: false });
1955        window.addEventListener('resize', applyBsnsrsltWheelScrollLenisPrevent2026);
1956        window.addEventListener('load', applyBsnsrsltWheelScrollLenisPrevent2026);
1957        document.addEventListener('click', function (e) {
1958            var tabBtn = e.target.closest && e.target.closest('.cck-sub .chart-wrap .btn-tab, .cck-sub .chart-wrap .select-btn');
1959            if (!tabBtn) {
1960                return;
1961            }
1962            setTimeout(applyBsnsrsltWheelScrollLenisPrevent2026, 0);
1963        });
1964    }
1965}
1966
1967/* =============================================================================
1968 * [임시] 함께하는 사람들 조직도 이미지맵 / 스크롤
1969 * -----------------------------------------------------------------------------
1970 * 모바일에서 이미지맵 coords가 원본 픽셀 기준이라 줄어든 이미지와 어긋남.
1971 * JSP는 수정하지 않고 보이는 이미지에 rwdImageMaps를 걸고
1972 * #baseWrap 기준으로 팀 리스트까지 스크롤한다.
1973 * 삭제 조건: 함께하는 사람들 JSP를 2026 마크업으로 전환 완료 시
1974 * ============================================================================= */
1975function initWpeopleOrgChart2026() {
1976    var $area = $('.chest-sub.wpeople .group-img-area');
1977    if (!$area.length) {
1978        return;
1979    }
1980
1981    function initOrgImageMaps() {
1982        var $img = $area.find('img[usemap]').filter(':visible');
1983        if (!$img.length || typeof $img.rwdImageMaps !== 'function') {
1984            return;
1985        }
1986        $img.each(function () {
1987            var img = this;
1988            var $imgEl = $(img);
1989            if ($imgEl.data('rwdMapInit')) {
1990                return;
1991            }
1992            var applyMap = function () {
1993                $imgEl.rwdImageMaps();
1994                $imgEl.data('rwdMapInit', true);
1995            };
1996            if (img.complete) {
1997                applyMap();
1998            } else {
1999                $imgEl.off('load.orgmap2026').on('load.orgmap2026', applyMap);
2000            }
2001        });
2002    }
2003
2004    function scrollToOrgTarget(target) {
2005        var wrap = document.getElementById('baseWrap');
2006        if (wrap) {
2007            var top = wrap.scrollTop + target.getBoundingClientRect().top - wrap.getBoundingClientRect().top;
2008            if (window.__lenis && typeof window.__lenis.scrollTo === 'function') {
2009                window.__lenis.scrollTo(top, { duration: 0.8 });
2010            } else {
2011                wrap.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
2012            }
2013            return;
2014        }
2015        target.scrollIntoView({ behavior: 'smooth', block: 'start' });
2016    }
2017
2018    function scrollToOrgHash() {
2019        var hash = window.location.hash;
2020        if (!hash || hash.length < 2) {
2021            return;
2022        }
2023        var target = document.getElementById(hash.substring(1));
2024        if (target) {
2025            scrollToOrgTarget(target);
2026        }
2027    }
2028
2029    function refreshMasonry() {
2030        if (typeof masonryGrid === 'function') {
2031            masonryGrid();
2032        }
2033    }
2034
2035    initOrgImageMaps();
2036    $(window).on('load', initOrgImageMaps);
2037    $(window).on('resize', initOrgImageMaps);
2038
2039    $area.on('click', 'area', function (e) {
2040        var href = $(this).attr('href');
2041        if (!href || href.charAt(0) !== '#') {
2042            return;
2043        }
2044        var target = document.getElementById(href.substring(1));
2045        if (!target) {
2046            return;
2047        }
2048        e.preventDefault();
2049        if (history.replaceState) {
2050            history.replaceState(null, '', href);
2051        }
2052        scrollToOrgTarget(target);
2053    });
2054
2055    if (typeof selectWpeopleListAfter === 'function') {
2056        var origSelectWpeopleListAfter = selectWpeopleListAfter;
2057        window.selectWpeopleListAfter = function (data) {
2058            origSelectWpeopleListAfter(data);
2059            refreshMasonry();
2060            scrollToOrgHash();
2061        };
2062    }
2063}
2064
2065/* =============================================================================
2066 * [임시] 아너 소사이어티 — URL cckIs 파라미터 탭 연동
2067 * -----------------------------------------------------------------------------
2068 * GNB/사이트맵 cckIs 링크로 진입 시 해당 탭을 연다.
2069 * JSP init()은 항상 첫 탭(0)을 열므로, init() 이후 goTabDisplay를 호출한다.
2070 * 삭제 조건: pr_hs_honorsocietyinfo JSP에서 cckIs 처리 전환 완료 시
2071 * ============================================================================= */
2072function initHonorsocietyCckIs2026() {
2073    if (!/\/pr\/hs\/initHonorsocietyinfo\.do/.test(window.location.pathname)) {
2074        return;
2075    }
2076
2077    var params = new URLSearchParams(window.location.search);
2078    if (params.get('honorSn')) {
2079        return;
2080    }
2081
2082    var cckIs = params.get('cckIs') || '';
2083    var tabIndex = null;
2084    if (cckIs === 'A') {
2085        tabIndex = 1;
2086    } else if (cckIs === 'B') {
2087        tabIndex = 2;
2088    } else if (cckIs === 'C') {
2089        tabIndex = 3;
2090    } else if (cckIs === 'D') {
2091        tabIndex = 4;
2092    }
2093
2094    if (tabIndex === null) {
2095        return;
2096    }
2097
2098    setTimeout(function () {
2099        if (typeof goTabDisplay === 'function') {
2100            goTabDisplay(tabIndex);
2101        }
2102    }, 0);
2103}
2104
2105/* =============================================================================
2106 * [임시] 개인정보 처리방침 — CSP inline handler 대체
2107 * -----------------------------------------------------------------------------
2108 * 운영 CSP가 onclick 및 nonce 없는 inline script 실행을 차단한다.
2109 * /sr/privacy.do 탭 전환·이전 방침 모달을 외부 JS에서 처리한다.
2110 * 삭제 조건: sr_privacy JSP에서 data-event + script nonce 전환 완료 시
2111 * ============================================================================= */
2112function srPrivacyGoTabDisplay2026(obj) {
2113    var $root = $('.chest-sub.privacy');
2114    $root.find('.ui-tab-pnl').attr({ 'aria-hidden': 'true' });
2115    $root.find('.ui-tab-btn').attr('class', 'ui-tab-btn').find('b.hide').remove();
2116    $root.find('#btn' + obj).attr('class', 'ui-tab-btn selected').append('<b class="hide">선택됨</b>');
2117    $root.find('#pnl' + obj + '.ui-tab-pnl').attr({ 'aria-hidden': 'false' });
2118}
2119
2120function srPrivacyModal2025_2026() {
2121    if (typeof $plugins === 'undefined' || typeof $plugins.uiModal !== 'function') {
2122        return;
2123    }
2124    $plugins.uiModal({
2125        id: 'modalPrivacy2025',
2126        link: '/contentHtml/privacy2025.html',
2127        remove: true,
2128        openback: function () {},
2129        closeback: function () {}
2130    });
2131}
2132
2133function initSrPrivacy2026() {
2134    if (!/\/sr\/privacy\.do/.test(window.location.pathname)) {
2135        return;
2136    }
2137
2138    var $root = $('.chest-sub.privacy');
2139    if (!$root.length) {
2140        return;
2141    }
2142
2143    srPrivacyGoTabDisplay2026(0);
2144
2145    $root.on('click', '#uiTabCCKI12_1 .ui-tab-btn', function (e) {
2146        e.preventDefault();
2147        var tabIndex = (this.id || '').substring(3);
2148        if (tabIndex === '') {
2149            return;
2150        }
2151        srPrivacyGoTabDisplay2026(tabIndex);
2152    });
2153
2154    $root.on('click', 'button.btn-base-imp', function (e) {
2155        var onclick = this.getAttribute('onclick') || '';
2156        if (onclick.indexOf('modalPrivacy2025') === -1) {
2157            return;
2158        }
2159        e.preventDefault();
2160        srPrivacyModal2025_2026();
2161    });
2162}
2163
2164/* =============================================================================
2165 * [임시] 기부 상세 — 지회 사이트 담당자 목록 필터
2166 * -----------------------------------------------------------------------------
2167 * 중앙회(001)는 전체 담당자를 보여주고, 지회 사이트는 해당 지회만 남긴다.
2168 * 경기(009)는 경기북부를 포함한다.
2169 * JSP setBhfInfo()는 전체를 그리므로, 렌더 후 #bhfInfo를 걸러낸다.
2170 * 삭제 조건: 각 기부 상세 JSP에서 지회 필터 전환 완료 시
2171 * ============================================================================= */
2172var BHF_KEYWORD_BY_CD_2026 = {
2173    '002': '서울',
2174    '003': '부산',
2175    '004': '대구',
2176    '005': '인천',
2177    '006': '광주',
2178    '007': '대전',
2179    '008': '울산',
2180    '009': '경기',
2181    '010': '강원',
2182    '011': '충북',
2183    '012': '충남',
2184    '013': '전북',
2185    '014': '전남',
2186    '015': '경북',
2187    '016': '경남',
2188    '017': '제주',
2189    '018': '세종'
2190};
2191
2192function applyBhfInfoFilter2026() {
2193    var branchCd = (window.cks && cks.__branchCd) ? String(cks.__branchCd).trim() : '';
2194    if (!branchCd || branchCd === '001') {
2195        return;
2196    }
2197
2198    var keyword = BHF_KEYWORD_BY_CD_2026[branchCd];
2199    if (!keyword) {
2200        return;
2201    }
2202
2203    var root = document.getElementById('bhfInfo');
2204    if (!root) {
2205        return;
2206    }
2207
2208    var rows = root.querySelectorAll('li.table-tr, .honor-item');
2209    for (var i = 0; i < rows.length; i++) {
2210        var row = rows[i];
2211        var th = row.querySelector('.table-th, .honor-table-th');
2212        var text = th ? (th.textContent || '') : '';
2213        if (text.indexOf(keyword) === -1) {
2214            if (row.parentNode) {
2215                row.parentNode.removeChild(row);
2216            }
2217        }
2218    }
2219
2220    var wraps = root.querySelectorAll('.honor-table-item');
2221    for (var j = 0; j < wraps.length; j++) {
2222        if (!wraps[j].querySelector('.honor-item') && wraps[j].parentNode) {
2223            wraps[j].parentNode.removeChild(wraps[j]);
2224        }
2225    }
2226}
2227
2228function initBhfInfoFilter2026() {
2229    if (!document.getElementById('bhfInfo') && typeof window.setBhfInfo !== 'function') {
2230        return;
2231    }
2232
2233    if (typeof window.setBhfInfo === 'function' && !window.setBhfInfo._bhfFilter2026) {
2234        var orig = window.setBhfInfo;
2235        var wrapped = function () {
2236            orig.apply(this, arguments);
2237            applyBhfInfoFilter2026();
2238        };
2239        wrapped._bhfFilter2026 = true;
2240        window.setBhfInfo = wrapped;
2241    }
2242
2243    applyBhfInfoFilter2026();
2244    setTimeout(applyBhfInfoFilter2026, 0);
2245}
2246
2247/**
2248 * 레거시 JSP의 ScrollTrigger.normalizeScroll(true)는 window 스크롤을 가로챔.
2249 * 2026 레이아웃은 #baseWrap이 스크롤 주체라 모바일 휠/터치가 막힘.
2250 * JSP는 수정하지 않고, 여기서 true 호출을 무시하고 기본 scroller를 #baseWrap으로 둔다.
2251 */
2252function initLegacyScrollTrigger2026() {
2253    if (typeof ScrollTrigger === 'undefined') {
2254        return;
2255    }
2256
2257    if (!ScrollTrigger._chest2026NormalizePatched) {
2258        ScrollTrigger._chest2026NormalizePatched = true;
2259        var origNormalize = ScrollTrigger.normalizeScroll.bind(ScrollTrigger);
2260        ScrollTrigger.normalizeScroll = function () {
2261            return origNormalize(false);
2262        };
2263    }
2264
2265    ScrollTrigger.normalizeScroll(false);
2266
2267    if (!window.__lenis && !usesDocumentScroll2026()) {
2268        var wrap = document.getElementById('baseWrap');
2269        if (wrap) {
2270            ScrollTrigger.defaults({ scroller: wrap });
2271        }
2272    }
2273}
2274
2275/**
2276 * 2026 smooth scroll (Lenis) — desktop only
2277 * 열매모아 레거시 본문은 #baseWrap 네이티브 스크롤 사용 (Lenis와 충돌 방지)
2278 * 2026 상세(.funding-view)는 레거시 프록시 대상이 아니다. Lenis는 initLenis2026에서 따로 끈다.
2279 */
2280function isLegacyCrwdfundPage2026() {
2281    if (document.querySelector('.funding-view')) {
2282        return false;
2283    }
2284    return !!(
2285        document.getElementById('crwdfundWrap') ||
2286        document.querySelector('#baseBody .campaign-sub.funding')
2287    );
2288}
2289
2290function isCrwdfundDetailDocScrollPath2026(path) {
2291    path = path || location.pathname || '';
2292    return path.indexOf('/ca/crwdfund/') !== -1 && path.indexOf('initCrwdfundDetail') !== -1;
2293}
2294
2295/**
2296 * 문서(window) 스크롤 페이지 — /bbs/1020/, 열매모아 상세
2297 * 클래스는 layout JSP에서 선적용. path 폴백은 레이아웃 누락 시에만.
2298 */
2299function ensureBbsCampaignClass2026() {
2300    var path = location.pathname || '';
2301    if (path.indexOf('/bbs/1020/') !== -1 || isCrwdfundDetailDocScrollPath2026(path)) {
2302        document.documentElement.classList.add('is-bbs-campaign');
2303    }
2304}
2305
2306/** is-bbs-campaign — #baseWrap 이 스크롤 포트로 남지 않도록 인라인 보정 */
2307function applyBbsCampaignDocumentScroll2026() {
2308    if (!document.documentElement.classList.contains('is-bbs-campaign')) {
2309        return;
2310    }
2311
2312    var wrap = document.getElementById('baseWrap');
2313    var content = document.getElementById('baseWrapContent');
2314    var bodyMain = document.getElementById('baseBody');
2315    var body = document.body;
2316    var locked = body && (
2317        body.classList.contains('is-gnb-open')
2318        || body.classList.contains('is-stmap-open')
2319        || body.classList.contains('is-legacy-modal-open')
2320    );
2321
2322    if (!locked) {
2323        document.documentElement.style.height = 'auto';
2324        document.documentElement.style.overflow = 'visible';
2325        if (body) {
2326            body.style.height = 'auto';
2327            body.style.overflow = 'visible';
2328        }
2329    }
2330
2331    if (wrap) {
2332        wrap.style.height = 'auto';
2333        wrap.style.maxHeight = 'none';
2334        wrap.style.overflow = 'visible';
2335    }
2336    if (content) {
2337        content.style.height = 'auto';
2338        content.style.maxHeight = 'none';
2339        content.style.overflow = 'visible';
2340    }
2341    if (bodyMain) {
2342        bodyMain.style.height = 'auto';
2343        bodyMain.style.minHeight = '0';
2344    }
2345}
2346window.applyBbsCampaignDocumentScroll2026 = applyBbsCampaignDocumentScroll2026;
2347
2348ensureBbsCampaignClass2026();
2349function scheduleApplyBbsCampaignDocumentScroll2026() {
2350    if (document.body) {
2351        applyBbsCampaignDocumentScroll2026();
2352    }
2353}
2354if (document.readyState === 'loading') {
2355    document.addEventListener('DOMContentLoaded', scheduleApplyBbsCampaignDocumentScroll2026);
2356} else {
2357    scheduleApplyBbsCampaignDocumentScroll2026();
2358}
2359
2360function isBbsHopeCampaignPage2026() {
2361    return document.documentElement.classList.contains('is-bbs-campaign');
2362}
2363
2364/** is-bbs-campaign: 스크롤 주체 = window (그 외 = #baseWrap / Lenis) */
2365function usesDocumentScroll2026() {
2366    return isBbsHopeCampaignPage2026();
2367}
2368
2369function getLayoutScrollY2026() {
2370    if (window.__lenis && typeof window.__lenis.scroll === 'number') {
2371        return window.__lenis.scroll;
2372    }
2373    if (usesDocumentScroll2026()) {
2374        return window.pageYOffset || document.documentElement.scrollTop || 0;
2375    }
2376    var wrap = document.getElementById('baseWrap');
2377    if (wrap) {
2378        return wrap.scrollTop;
2379    }
2380    return window.pageYOffset || document.documentElement.scrollTop || 0;
2381}
2382
2383function setLayoutScrollY2026(y, options) {
2384    var opts = options || {};
2385    if (usesDocumentScroll2026()) {
2386        if (opts.smooth) {
2387            window.scrollTo({ top: y, behavior: 'smooth' });
2388        } else {
2389            window.scrollTo(0, y);
2390        }
2391        return;
2392    }
2393    if (window.__lenis && typeof window.__lenis.scrollTo === 'function') {
2394        window.__lenis.scrollTo(y, opts.lenis || { immediate: !opts.smooth, duration: opts.smooth ? 1.2 : 0 });
2395        return;
2396    }
2397    var wrap = document.getElementById('baseWrap');
2398    if (wrap) {
2399        if (opts.smooth && typeof wrap.scrollTo === 'function') {
2400            wrap.scrollTo({ top: y, behavior: 'smooth' });
2401        } else {
2402            wrap.scrollTop = y;
2403        }
2404        return;
2405    }
2406    window.scrollTo(0, y);
2407}
2408
2409function bindLayoutScroll2026(handler) {
2410    if (window.__lenis && typeof window.__lenis.on === 'function') {
2411        window.__lenis.on('scroll', handler);
2412        return;
2413    }
2414    if (usesDocumentScroll2026()) {
2415        window.addEventListener('scroll', handler, { passive: true });
2416        return;
2417    }
2418    var wrap = document.getElementById('baseWrap');
2419    if (wrap) {
2420        wrap.addEventListener('scroll', handler, { passive: true });
2421    } else {
2422        window.addEventListener('scroll', handler, { passive: true });
2423    }
2424}
2425
2426/* =============================================================================
2427 * [임시] 열매모아 레거시 스크롤 프록시
2428 * -----------------------------------------------------------------------------
2429 * 2026 레이아웃은 html/body overflow:hidden, #baseWrap overflow-y:auto 구조라
2430 * window.scrollY 가 항상 0. 레거시 JSP(ca_crwdfund_detail_003 등)는 window 기준
2431 * 스크롤을 쓰므로, 열매모아 페이지에서만 window.scrollY / scroll 이벤트를
2432 * #baseWrap 으로 프록시한다.
2433 * 삭제 조건: 열매모아 레거시 JSP(ca_crwdfund_detail_003 등)를 2026 레이아웃에서 더 이상 서빙하지 않을 때
2434 * 2026 상세(.funding-view)는 isLegacyCrwdfundPage2026() 에서 제외되어 이 프록시를 타지 않는다.
2435 * ============================================================================= */
2436function initLegacyCrwdfundScrollProxy2026() {
2437    if (!isLegacyCrwdfundPage2026()) {
2438        return;
2439    }
2440
2441    var baseWrap = document.getElementById('baseWrap');
2442    if (!baseWrap) {
2443        return;
2444    }
2445
2446    // [임시] 퀵링크 숨김 — 열매모아 레거시 본문에서 퀵링크 미노출
2447    var ql = document.querySelector('.quick-link');
2448    if (ql) ql.style.display = 'none';
2449
2450    // window.scrollY / pageYOffset → #baseWrap.scrollTop
2451    try {
2452        Object.defineProperty(window, 'scrollY', {
2453            get: function () { return baseWrap.scrollTop; },
2454            configurable: true
2455        });
2456        Object.defineProperty(window, 'pageYOffset', {
2457            get: function () { return baseWrap.scrollTop; },
2458            configurable: true
2459        });
2460    } catch (e) { /* IE 등 예외 무시 */ }
2461
2462    // [임시] 레거시 fund-card 축소 — JSP 는 document scroll + window.scrollY > 200 으로
2463    // #fund-banner.f_bann 에 .fixed 를 붙임. scroll 은 버블링되지 않아 #baseWrap 스크롤만으로는
2464    // document 리스너가 호출되지 않으므로 여기서 직접 토글한다.
2465    function syncLegacyFundBannerFixed2026() {
2466        var banners = document.querySelectorAll('.f_bann');
2467        if (!banners.length) {
2468            return;
2469        }
2470        var shouldFix = window.innerWidth > 500 && baseWrap.scrollTop > 200;
2471        for (var i = 0; i < banners.length; i++) {
2472            banners[i].classList.toggle('fixed', shouldFix);
2473        }
2474    }
2475
2476    // #baseWrap scroll → window/document 'scroll' 이벤트 중계
2477    baseWrap.addEventListener('scroll', function () {
2478        window.dispatchEvent(new Event('scroll'));
2479        document.dispatchEvent(new Event('scroll'));
2480        syncLegacyFundBannerFixed2026();
2481    }, { passive: true });
2482
2483    window.addEventListener('resize', syncLegacyFundBannerFixed2026);
2484    syncLegacyFundBannerFixed2026();
2485
2486    // jQuery $(window).scrollTop() 패치
2487    if (window.jQuery) {
2488        var origScrollTop = jQuery.fn.scrollTop;
2489        jQuery.fn.scrollTop = function (val) {
2490            if (this[0] === window || this[0] === document) {
2491                if (val === undefined) return baseWrap.scrollTop;
2492                baseWrap.scrollTop = val;
2493                return this;
2494            }
2495            return origScrollTop.apply(this, arguments);
2496        };
2497    }
2498}
2499
2500/**
2501 * jQuery UI datepicker는 #ui-datepicker-div 를 body 직속에 position:absolute 로 붙인다.
2502 * 2026 레이아웃은 html/body overflow:hidden, 스크롤 주체가 #baseWrap(Lenis)이라
2503 * window.scrollY 가 항상 0 → 달력 top 이 스크롤과 무관하게 viewport 에 남는다.
2504 * 입력칸 getBoundingClientRect 기준으로 position:fixed 재배치한다.
2505 */
2506function initJqDatepickerViewportFix2026() {
2507    if (!window.jQuery || !jQuery.datepicker || jQuery.datepicker.__viewportFix2026) {
2508        return;
2509    }
2510    jQuery.datepicker.__viewportFix2026 = true;
2511
2512    function positionJqDatepicker2026(input, dpDiv, force) {
2513        if (!input || !dpDiv || !dpDiv.length) {
2514            return;
2515        }
2516        if (!force && dpDiv.is(':hidden')) {
2517            return;
2518        }
2519        var rect = input.getBoundingClientRect();
2520        if (rect.bottom < 0 || rect.top > window.innerHeight) {
2521            jQuery.datepicker._hideDatepicker();
2522            return;
2523        }
2524        var top = rect.bottom + 2;
2525        var left = rect.left;
2526        var dpWidth = dpDiv.outerWidth();
2527        var dpHeight = dpDiv.outerHeight();
2528        if (left + dpWidth > window.innerWidth - 8) {
2529            left = Math.max(8, window.innerWidth - dpWidth - 8);
2530        }
2531        if (top + dpHeight > window.innerHeight - 8) {
2532            top = Math.max(8, rect.top - dpHeight - 2);
2533        }
2534        dpDiv.css({
2535            position: 'fixed',
2536            top: top + 'px',
2537            left: left + 'px',
2538            zIndex: 400
2539        });
2540    }
2541
2542    var origShowDatepicker = jQuery.datepicker._showDatepicker;
2543    jQuery.datepicker._showDatepicker = function () {
2544        origShowDatepicker.apply(this, arguments);
2545        var inst = this._curInst;
2546        if (inst && inst.input && inst.input[0]) {
2547            positionJqDatepicker2026(inst.input[0], inst.dpDiv, true);
2548        }
2549    };
2550
2551    function repositionOpenJqDatepicker2026() {
2552        var inst = jQuery.datepicker._curInst;
2553        if (!inst || !inst.dpDiv || inst.dpDiv.is(':hidden')) {
2554            return;
2555        }
2556        if (inst.input && inst.input[0]) {
2557            positionJqDatepicker2026(inst.input[0], inst.dpDiv);
2558        }
2559    }
2560
2561    var baseWrap = document.getElementById('baseWrap');
2562    if (baseWrap) {
2563        baseWrap.addEventListener('scroll', repositionOpenJqDatepicker2026, true);
2564    }
2565    window.addEventListener('resize', repositionOpenJqDatepicker2026);
2566    if (window.__lenis && typeof window.__lenis.on === 'function') {
2567        window.__lenis.on('scroll', repositionOpenJqDatepicker2026);
2568    }
2569}
2570
2571/* =============================================================================
2572 * [임시] 레거시 .modal(기부상담 등) — iOS 푸터 합성 / #baseWrap 스크롤 잠금
2573 * -----------------------------------------------------------------------------
2574 * 레거시 팝업이 #baseBody 안에 있어 #baseWrap overflow 스크롤과 충돌함.
2575 * 열림/닫힘은 computed opacity(transition)로 추측하지 않고 클릭 의도로 토글한다.
2576 * 삭제 조건: 리뉴얼 팝업을 footer와 동등한 구조(#baseWrap 형제)로 만들면 이 함수 전체 삭제
2577 * ============================================================================= */
2578function initLegacyModalLock2026() {
2579    var wrap = document.getElementById('baseWrap');
2580    if (!wrap) {
2581        return;
2582    }
2583
2584    function setLegacyModalOpen2026(isOpen) {
2585        var $body = $(document.body);
2586        if (isOpen) {
2587            $body.addClass('is-legacy-modal-open');
2588            if (window.__lenis && typeof window.__lenis.stop === 'function') {
2589                window.__lenis.stop();
2590            }
2591            if (typeof window.__hideHeaderBar === 'function') {
2592                window.__hideHeaderBar();
2593            }
2594            return;
2595        }
2596        $body.removeClass('is-legacy-modal-open');
2597        $body.css('overflow', '');
2598        if (window.__lenis && typeof window.__lenis.start === 'function') {
2599            window.__lenis.start();
2600        }
2601        if (typeof applyBbsCampaignDocumentScroll2026 === 'function') {
2602            applyBbsCampaignDocumentScroll2026();
2603        }
2604        if (typeof window.__syncHeaderScrollState === 'function') {
2605            window.__syncHeaderScrollState();
2606        }
2607    }
2608
2609    $(document).on('click', '.btn-popup[data-popup]', function () {
2610        var id = $(this).attr('data-popup') || $(this).data('popup');
2611        if (!id) {
2612            return;
2613        }
2614        var $modal = $('#' + id);
2615        if (!$modal.hasClass('modal')) {
2616            return;
2617        }
2618        setLegacyModalOpen2026(true);
2619    });
2620
2621    $(document).on('click', '.btn-popup-ty1, .btn-popup-close', function () {
2622        if (!$(this).closest('.modal').length) {
2623            return;
2624        }
2625        setLegacyModalOpen2026(false);
2626    });
2627
2628    wrap.addEventListener('touchmove', function (e) {
2629        if (!document.body.classList.contains('is-legacy-modal-open')) {
2630            return;
2631        }
2632        if (e.target.closest && e.target.closest('.popup-area, .popup-wrap, .layer-popup')) {
2633            return;
2634        }
2635        e.preventDefault();
2636    }, { passive: false });
2637}
2638
2639function initLenis2026() {
2640    if (typeof Lenis === 'undefined') {
2641        return;
2642    }
2643
2644    if (isLegacyCrwdfundPage2026()) {
2645        return;
2646    }
2647
2648    /* 열매모아 상세: contentHtml(AOS/Swiper/100vh)과 Lenis 충돌 방지 — #baseWrap 네이티브 스크롤 */
2649    if (document.querySelector('.funding-view')) {
2650        return;
2651    }
2652
2653    /* /bbs/1020/(is-bbs-campaign): 문서 스크롤 — Lenis 미사용 */
2654    if (isBbsHopeCampaignPage2026()) {
2655        return;
2656    }
2657
2658    if (window.innerWidth < 1024) {
2659        return;
2660    }
2661
2662    var wrapper = document.getElementById('baseWrap');
2663    var content = document.getElementById('baseWrapContent');
2664    if (!wrapper || !content) {
2665        return;
2666    }
2667
2668    var lenis = new Lenis({
2669        wrapper: wrapper,
2670        content: content
2671    });
2672    window.__lenis = lenis;
2673
2674    if (typeof gsap !== 'undefined' && gsap.ticker) {
2675        gsap.ticker.add(function (time) {
2676            lenis.raf(time * 1000);
2677        });
2678        gsap.ticker.lagSmoothing(0);
2679    } else {
2680        function raf(time) {
2681            lenis.raf(time);
2682            requestAnimationFrame(raf);
2683        }
2684        requestAnimationFrame(raf);
2685    }
2686
2687    initScrollTriggerLenisBridge2026();
2688
2689    requestAnimationFrame(function () {
2690        applyLenisPreventToNestedScroll2026();
2691        applyBsnsrsltWheelScrollLenisPrevent2026();
2692    });
2693
2694    initLenisNestedScrollTabRescan2026();
2695
2696    // 페이지 하단 GSAP 초기화(document.ready) 이후 ScrollTrigger 재계산
2697    setTimeout(function () {
2698        initScrollTriggerLenisBridge2026();
2699    }, 0);
2700}
2701
2702/**
2703 * AOS는 window.pageYOffset 기준이라 #baseWrap / Lenis 스크롤과 맞지 않음.
2704 * - scroll 시 AOS.refresh 연결
2705 * - IntersectionObserver로 viewport 진입 시 aos-animate 부여 (Lenis 호환)
2706 * - AJAX 삽입 콘텐츠는 refreshAosForLenis2026 / injectHtmlWithScripts2026 사용
2707 */
2708function initAosBridge2026() {
2709    var wrap = document.getElementById('baseWrap');
2710    var scheduled = false;
2711
2712    function refreshAos() {
2713        // IntersectionObserver가 Lenis 호환 애니메이션을 담당.
2714        // AOS.refresh는 인라인 AOS.init 콘텐츠의 위치 재계산용.
2715        if (!window.AOS) {
2716            return; 
2717        }
2718        if (scheduled) {
2719            return;
2720        }
2721        scheduled = true;
2722        requestAnimationFrame(function () {
2723            scheduled = false;
2724            if (typeof AOS.refresh === 'function') {
2725                AOS.refresh();
2726            }
2727        });
2728    }
2729
2730    function patchAosInit() {
2731        if (!window.AOS || typeof AOS.init !== 'function' || AOS.__initPatched2026) {
2732            return;
2733        }
2734        var originalInit = AOS.init.bind(AOS);
2735        AOS.init = function () {
2736            var result = originalInit.apply(AOS, arguments);
2737            refreshAos();
2738            observeAosElements2026(document.getElementById('htmlDiv') || document);
2739            return result;
2740        };
2741        AOS.__initPatched2026 = true;
2742    }
2743
2744    /* is-bbs-campaign: 스크롤마다 AOS.refresh 하면 손스크롤이 끊김 — IO가 담당 */
2745    if (!isBbsHopeCampaignPage2026()) {
2746        if (wrap && !wrap.__aosBridgeBound) {
2747            wrap.__aosBridgeBound = true;
2748            wrap.addEventListener('scroll', refreshAos, { passive: true });
2749        }
2750
2751        if (window.__lenis && !window.__lenis.__aosBridgeBound) {
2752            window.__lenis.__aosBridgeBound = true;
2753            window.__lenis.on('scroll', refreshAos);
2754        }
2755    }
2756
2757    ensureAosIntersectionObserver2026();
2758    observeAosElements2026(document);
2759    bindBbsCampaignHtmlDivAos2026();
2760
2761    patchAosInit();
2762    // jhead에서 aos.js가 ui.common 뒤에 로드되는 경우 대비
2763    if (!window.AOS) {
2764        setTimeout(patchAosInit, 0);
2765        setTimeout(patchAosInit, 300);
2766    }
2767}
2768
2769/** #baseWrap 기준 IntersectionObserver — Lenis 스크롤에서도 AOS 클래스 적용 */
2770function ensureAosIntersectionObserver2026() {
2771    if (window.__aosIo2026 || typeof window.IntersectionObserver !== 'function') {
2772        return window.__aosIo2026 || null;
2773    }
2774
2775    var root = usesDocumentScroll2026() ? null : (document.getElementById('baseWrap') || null);
2776    window.__aosIo2026 = new IntersectionObserver(function (entries) {
2777        entries.forEach(function (entry) {
2778            var el = entry.target;
2779            if (entry.isIntersecting) {
2780                el.classList.add('aos-init', 'aos-animate');
2781            } else if (el.getAttribute('data-aos-once') === 'false') {
2782                el.classList.remove('aos-animate');
2783            }
2784        });
2785    }, {
2786        root: root,
2787        rootMargin: '0px 0px -8% 0px',
2788        threshold: 0.08
2789    });
2790
2791    return window.__aosIo2026;
2792}
2793
2794/**
2795 * is-bbs-campaign — contentHtml AJAX 삽입 후 [data-aos] 관찰
2796 */
2797function bindBbsCampaignHtmlDivAos2026() {
2798    if (!isBbsHopeCampaignPage2026() || typeof MutationObserver !== 'function') {
2799        return;
2800    }
2801    var htmlDiv = document.getElementById('htmlDiv');
2802    if (!htmlDiv || htmlDiv.__aosMo2026) {
2803        return;
2804    }
2805    htmlDiv.__aosMo2026 = true;
2806
2807    var timer = null;
2808    function bindInjectedAos() {
2809        if (timer) {
2810            clearTimeout(timer);
2811        }
2812        timer = setTimeout(function () {
2813            refreshAosForLenis2026(htmlDiv);
2814            if (typeof applyBbsCampaignDocumentScroll2026 === 'function') {
2815                applyBbsCampaignDocumentScroll2026();
2816            }
2817        }, 0);
2818    }
2819
2820    var mo = new MutationObserver(bindInjectedAos);
2821    mo.observe(htmlDiv, { childList: true, subtree: true });
2822
2823    if (htmlDiv.querySelector('[data-aos]')) {
2824        bindInjectedAos();
2825    }
2826}
2827
2828function observeAosElements2026(scope) {
2829    var root = scope && scope.querySelectorAll ? scope : document;
2830    var nodes = root.querySelectorAll ? root.querySelectorAll('[data-aos]') : [];
2831    if (!nodes.length) {
2832        return;
2833    }
2834
2835    var io = ensureAosIntersectionObserver2026();
2836    Array.prototype.forEach.call(nodes, function (el) {
2837        el.classList.add('aos-init');
2838        if (io) {
2839            io.observe(el);
2840        } else {
2841            el.classList.add('aos-animate');
2842        }
2843    });
2844}
2845
2846/** AJAX 등으로 [data-aos]가 추가된 뒤 호출 */
2847function refreshAosForLenis2026(scope) {
2848    if (window.AOS) {
2849        if (typeof AOS.refreshHard === 'function') {
2850            AOS.refreshHard();
2851        } else if (typeof AOS.refresh === 'function') {
2852            AOS.refresh();
2853        }
2854    }
2855    observeAosElements2026(scope || document);
2856}
2857window.refreshAosForLenis2026 = refreshAosForLenis2026;
2858
2859/**
2860 * contentHtml 등 상대 경로를 절대 경로로 보정
2861 * @param {string} url
2862 * @param {string} baseUrl 예: /contentHtml/crwdfund/9324/
2863 */
2864function resolveContentUrl2026(url, baseUrl) {
2865    if (!url || !baseUrl) {
2866        return url;
2867    }
2868    if (/^(https?:|\/\/|data:|blob:)/i.test(url) || url.charAt(0) === '/') {
2869        return url;
2870    }
2871    try {
2872        return new URL(url, window.location.origin + baseUrl).pathname + (new URL(url, window.location.origin + baseUrl).search || '');
2873    } catch (e) {
2874        return baseUrl.replace(/\/?$/, '/') + url.replace(/^\.\//, '');
2875    }
2876}
2877
2878/**
2879 * AJAX HTML을 컨테이너에 넣고 script(외부/module/inline)를 재실행.
2880 * contentHtml의 type=module + AOS/Swiper 초기화용.
2881 * @param {string|Element|jQuery} target
2882 * @param {string} html
2883 * @param {{nonce?: string, baseUrl?: string}} [options]
2884 * @returns {Promise<void>}
2885 */
2886function injectHtmlWithScripts2026(target, html, options) {
2887    options = options || {};
2888    var nonce = options.nonce || '';
2889    var baseUrl = options.baseUrl || '';
2890    var el = target && target.jquery ? target[0] : (typeof target === 'string' ? document.querySelector(target) : target);
2891
2892    if (!el || typeof html !== 'string') {
2893        return Promise.resolve();
2894    }
2895
2896    var parser = new DOMParser();
2897    var doc = parser.parseFromString(html, 'text/html');
2898    var scripts = Array.prototype.slice.call(doc.querySelectorAll('script'));
2899    scripts.forEach(function (s) {
2900        if (s.parentNode) {
2901            s.parentNode.removeChild(s);
2902        }
2903    });
2904
2905    if (baseUrl) {
2906        Array.prototype.forEach.call(doc.querySelectorAll('[src], [href]'), function (node) {
2907            if (node.hasAttribute('src')) {
2908                node.setAttribute('src', resolveContentUrl2026(node.getAttribute('src'), baseUrl));
2909            }
2910            if (node.hasAttribute('href') && node.tagName === 'LINK') {
2911                node.setAttribute('href', resolveContentUrl2026(node.getAttribute('href'), baseUrl));
2912            }
2913        });
2914    }
2915
2916    var parts = [];
2917    Array.prototype.forEach.call(doc.querySelectorAll('head link[rel="stylesheet"]'), function (link) {
2918        parts.push(link.outerHTML);
2919    });
2920    parts.push(doc.body ? doc.body.innerHTML : html);
2921    el.innerHTML = parts.join('');
2922
2923    function runOne(oldScript) {
2924        return new Promise(function (resolve) {
2925            var s = document.createElement('script');
2926            var type = oldScript.getAttribute('type') || oldScript.type || '';
2927            if (type) {
2928                s.type = type;
2929            }
2930            if (nonce) {
2931                s.setAttribute('nonce', nonce);
2932            }
2933
2934            Array.prototype.forEach.call(oldScript.attributes || [], function (attr) {
2935                if (attr.name === 'nonce' || attr.name === 'type' || attr.name === 'src') {
2936                    return;
2937                }
2938                s.setAttribute(attr.name, attr.value);
2939            });
2940
2941            var srcAttr = oldScript.getAttribute('src');
2942            if (srcAttr) {
2943                s.src = resolveContentUrl2026(srcAttr, baseUrl);
2944                s.onload = function () { resolve(); };
2945                s.onerror = function () { resolve(); };
2946                (document.body || el).appendChild(s);
2947            } else {
2948                s.text = oldScript.textContent || '';
2949                (document.body || el).appendChild(s);
2950                resolve();
2951            }
2952        });
2953    }
2954
2955    var chain = Promise.resolve();
2956    scripts.forEach(function (oldScript) {
2957        chain = chain.then(function () {
2958            return runOne(oldScript);
2959        });
2960    });
2961
2962    return chain.then(function () {
2963        // 모듈 내 AOS.init 직후 DOM 반영 대기
2964        requestAnimationFrame(function () {
2965            refreshAosForLenis2026(el);
2966            applyLenisPreventToNestedScroll2026(el);
2967            applyBsnsrsltWheelScrollLenisPrevent2026();
2968            initScrollTriggerLenisBridge2026();
2969            if (typeof applyBbsCampaignDocumentScroll2026 === 'function') {
2970                applyBbsCampaignDocumentScroll2026();
2971            }
2972        });
2973    });
2974}
2975window.injectHtmlWithScripts2026 = injectHtmlWithScripts2026;
2976
2977/**
2978 * 2026 floating quick link — top scroll, footer overlap
2979 */
2980function initQuickLink2026() {
2981    var quickLink = document.getElementById('quickLink');
2982    var footer = document.getElementById('baseFooter');
2983    var topBtn = quickLink && quickLink.querySelector('.quick-link__top');
2984    var footerActive = false;
2985    var lastBottom = null;
2986    var gap = 32;
2987
2988    if (!quickLink) {
2989        return;
2990    }
2991
2992    if (topBtn) {
2993        topBtn.addEventListener('click', function () {
2994            setLayoutScrollY2026(0, { smooth: true, lenis: { duration: 1.2 } });
2995        });
2996    }
2997
2998    var MOBILE_MAX = 1024;
2999
3000    function isQuickLinkMobile() {
3001        return window.innerWidth <= MOBILE_MAX;
3002    }
3003
3004    function getDefaultBottom(viewHeight) {
3005        return window.innerWidth <= 1199 ? 16 : Math.round(viewHeight * 0.1);
3006    }
3007
3008    function clearQuickLinkBottom() {
3009        lastBottom = null;
3010        quickLink.style.bottom = '';
3011    }
3012
3013    function setQuickLinkBottom(bottom) {
3014        if (isQuickLinkMobile()) {
3015            return;
3016        }
3017        if (bottom === lastBottom) {
3018            return;
3019        }
3020        lastBottom = bottom;
3021        quickLink.style.bottom = bottom + 'px';
3022    }
3023
3024    function applyDefaultBottom() {
3025        if (isQuickLinkMobile()) {
3026            clearQuickLinkBottom();
3027            return;
3028        }
3029        setQuickLinkBottom(getDefaultBottom(window.innerHeight));
3030    }
3031
3032    function updateQuickLinkPosition() {
3033        if (isQuickLinkMobile()) {
3034            clearQuickLinkBottom();
3035            return;
3036        }
3037        if (!footer) {
3038            return;
3039        }
3040
3041        var viewHeight = window.innerHeight;
3042        var footerTop = footer.getBoundingClientRect().top;
3043        var bottom;
3044
3045        if (footerTop >= viewHeight) {
3046            bottom = getDefaultBottom(viewHeight);
3047        } else {
3048            bottom = viewHeight - footerTop + gap;
3049        }
3050
3051        setQuickLinkBottom(bottom);
3052    }
3053
3054    function onQuickLinkScroll() {
3055        if (footerActive) {
3056            updateQuickLinkPosition();
3057        }
3058    }
3059
3060    if (footer) {
3061        if ('IntersectionObserver' in window) {
3062            new IntersectionObserver(function (entries) {
3063                footerActive = entries[0].isIntersecting;
3064                if (footerActive) {
3065                    updateQuickLinkPosition();
3066                } else {
3067                    lastBottom = null;
3068                    applyDefaultBottom();
3069                }
3070            }, { threshold: 0 }).observe(footer);
3071        } else {
3072            footerActive = true;
3073        }
3074
3075        bindLayoutScroll2026(onQuickLinkScroll);
3076
3077        window.addEventListener('resize', function () {
3078            lastBottom = null;
3079            if (isQuickLinkMobile()) {
3080                clearQuickLinkBottom();
3081                return;
3082            }
3083            if (footerActive) {
3084                updateQuickLinkPosition();
3085            } else {
3086                applyDefaultBottom();
3087            }
3088        });
3089
3090        applyDefaultBottom();
3091    }
3092
3093    var skipToBody = document.querySelector('#baseSkip a[href="#baseBody"]');
3094    var mainEl = document.getElementById('baseBody');
3095    if (skipToBody && mainEl) {
3096        skipToBody.addEventListener('click', function () {
3097            setTimeout(function () {
3098                mainEl.focus();
3099            }, 0);
3100        });
3101    }
3102}
3103
3104function navCommon() {
3105    const header = document.querySelector('#baseHeader') || document.querySelector('.header.type2');
3106    const headerMo = document.querySelector('.header-mo');
3107    const campaignBanner = document.querySelector('.header-campaign');
3108    let prevScroll = window.pageYOffset;
3109    const bannerHeight = campaignBanner ? campaignBanner.clientHeight : 0;
3110    var HEADER_ACTIVE_OFFSET = 40;
3111    var isFundingViewPage = !!document.querySelector('.funding-view');
3112
3113    // 초기 설정
3114    if (header) {
3115        if (bannerHeight > 0) {
3116            header.style.position = 'absolute';
3117            header.style.top = '0';
3118        } else {
3119            header.style.position = 'fixed';
3120            header.style.top = '0';
3121        }
3122    }
3123    
3124    function closeHeaderSelectsByScroll() {
3125
3126        /* -----------------
3127         * 지회 선택 dropdown
3128         * ----------------- */
3129        if ($('.btn-region').hasClass('active')) {
3130          $('.region-wrap, .btn-region').removeClass('active');
3131          $('.btn-region').attr('aria-expanded', 'false');
3132          $('.region-list a').attr('tabindex', '-1');
3133        }
3134
3135        /* -----------------
3136         * 언어권 선택 dropdown
3137         * ----------------- */
3138        $('.select-list-wrap > button.active').each(function () {
3139          const $button = $(this);
3140          const $menu = $button.siblings('ul');
3141
3142          $button.removeClass('active')
3143                 .attr('aria-expanded', 'false');
3144
3145          $menu.removeClass('active');
3146        });
3147
3148        /* -----------------
3149         * 나의 기부내역 dropdown
3150         * ----------------- */
3151        var $donationBtn = $('.header__dropdown--donation .btn.mydonation');
3152        var $donationMenu = $('.header__dropdown--donation .select-list.mydonation');
3153        if ($donationBtn.hasClass('active')) {
3154          $donationBtn.removeClass('active').attr('aria-expanded', 'false');
3155          $donationMenu.removeClass('active');
3156        }
3157      }
3158
3159    function getScrollY() {
3160        return getLayoutScrollY2026();
3161    }
3162
3163    function updateHeaderPositionMode(currentScroll) {
3164        if (bannerHeight > 0) {
3165            if (currentScroll >= bannerHeight && header.style.position !== 'fixed') {
3166                header.style.position = 'fixed';
3167                header.style.top = '-' + bannerHeight + 'px';
3168            } else if (currentScroll < bannerHeight && header.style.position !== 'absolute') {
3169                header.style.position = 'absolute';
3170                header.style.top = '0';
3171            }
3172        }
3173    }
3174
3175    function isLegacyModalOpen() {
3176        return document.body.classList.contains('is-legacy-modal-open');
3177    }
3178
3179    function showHeaderBar() {
3180        if (isLegacyModalOpen()) {
3181            return;
3182        }
3183        header.classList.add('active');
3184        header.style.transform = 'translateY(0)';
3185        header.style.webkitTransform = 'translateY(0)';
3186    }
3187
3188    function hideHeaderBar() {
3189        var isMoMenuOpen = headerMo && headerMo.classList.contains('active');
3190        var isStmapOpen = document.body.classList.contains('is-stmap-open');
3191        var isGnbOpen = document.body.classList.contains('is-gnb-open');
3192        if (!isMoMenuOpen && !isStmapOpen && !isGnbOpen) {
3193            var headerInner = header.querySelector('.header-inner');
3194            var headerHeight = headerInner ? headerInner.clientHeight : header.offsetHeight;
3195            header.style.transform = 'translateY(-' + headerHeight + 'px)';
3196            header.style.webkitTransform = 'translateY(-' + headerHeight + 'px)';
3197            closeHeaderSelectsByScroll();
3198        }
3199    }
3200
3201    /**
3202     * 새로고침·bfcache 복귀 시 스크롤 위치에 맞춰 헤더 노출/배경 동기화
3203     */
3204    function syncHeaderScrollState() {
3205        if (!header) {
3206            return;
3207        }
3208
3209        if (isLegacyModalOpen()) {
3210            hideHeaderBar();
3211            prevScroll = getScrollY();
3212            return;
3213        }
3214
3215        if (headerMo && headerMo.classList.contains('active')) {
3216            header.style.position = 'fixed';
3217            header.style.top = '0';
3218            header.style.transform = 'none';
3219            header.style.webkitTransform = 'none';
3220            prevScroll = getScrollY();
3221            return;
3222        }
3223
3224        var currentScroll = getScrollY();
3225        updateHeaderPositionMode(currentScroll);
3226
3227        header.style.transform = 'translateY(0)';
3228        header.style.webkitTransform = 'translateY(0)';
3229
3230        if (header.style.position !== 'fixed') {
3231            header.style.top = '0';
3232        }
3233
3234        if (currentScroll > HEADER_ACTIVE_OFFSET) {
3235            header.classList.add('active');
3236            if (isFundingViewPage) {
3237                hideHeaderBar();
3238            }
3239        } else {
3240            header.classList.remove('active');
3241        }
3242
3243        prevScroll = currentScroll;
3244    }
3245
3246    function onHeaderScroll() {
3247        if (!header) {
3248            return;
3249        }
3250
3251        var currentScroll = getScrollY();
3252
3253        if (isLegacyModalOpen()) {
3254            hideHeaderBar();
3255            prevScroll = currentScroll;
3256            return;
3257        }
3258
3259        /* ==================================
3260         * 모바일 메뉴 활성 상태
3261         * → 헤더 상태 강제 고정
3262         * ================================== */
3263        if (headerMo && headerMo.classList.contains('active')) {
3264            header.style.position = 'fixed';
3265            header.style.top = '0';
3266            header.style.transform = 'none';
3267            header.style.webkitTransform = 'none';
3268
3269            prevScroll = currentScroll;
3270            return;
3271        }
3272
3273        updateHeaderPositionMode(currentScroll);
3274
3275        // fixed 상태일 때만 show/hide 로직 작동
3276        if (header.style.position === 'fixed') {
3277            if (currentScroll <= HEADER_ACTIVE_OFFSET || (prevScroll >= currentScroll && !isFundingViewPage)) {
3278                // 임계값 이하이거나(또는 일반 페이지에서 스크롤 올릴 때) 헤더 보이기
3279                // 열매모아 상세(.funding-view)는 sticky 제목바와 겹치지 않도록 휠 업에서도 헤더를 열지 않음
3280                showHeaderBar();
3281            } else {
3282                // 임계값 초과 + 스크롤 내릴 때(또는 열매모아 상세에서 휠 업) - 헤더 숨기기
3283                hideHeaderBar();
3284            }
3285
3286            // 숨김 여부와 별개로 스크롤 임계값에 맞춰 배경(active) 유지
3287            if (currentScroll > HEADER_ACTIVE_OFFSET) {
3288                header.classList.add('active');
3289            }
3290        } else {
3291            // absolute 상태일 때는 transform 초기화
3292            header.style.transform = 'translateY(0)';
3293            header.style.webkitTransform = 'translateY(0)';
3294            header.style.top = '0';
3295
3296            if (currentScroll > HEADER_ACTIVE_OFFSET) {
3297                header.classList.add('active');
3298            }
3299        }
3300
3301        // 임계값 이하일 때
3302        if (currentScroll <= HEADER_ACTIVE_OFFSET) {
3303            header.classList.remove('active');
3304        }
3305
3306        prevScroll = currentScroll;
3307    }
3308
3309    bindLayoutScroll2026(onHeaderScroll);
3310
3311    window.__syncHeaderScrollState = syncHeaderScrollState;
3312    window.__hideHeaderBar = hideHeaderBar;
3313
3314    syncHeaderScrollState();
3315    requestAnimationFrame(syncHeaderScrollState);
3316    setTimeout(syncHeaderScrollState, 0);
3317    window.addEventListener('pageshow', syncHeaderScrollState);
3318
3319    const searchBtn = document.querySelector('.btn-search');
3320    const searchWrap = document.querySelector('.search-wrap');
3321    const regionBtn = document.querySelector('.btn-region');
3322    const regionWrap = document.querySelector('.region-wrap');
3323
3324    if (searchBtn) {
3325        searchBtn.addEventListener('click', () => {
3326            if (searchBtn.classList.contains('active')) {
3327                searchBtn.classList.remove('active');
3328                searchWrap.classList.remove('active');
3329                header.classList.remove('on');
3330            } else {
3331                searchBtn.classList.add('active');
3332                searchWrap.classList.add('active');
3333                header.classList.add('on');
3334                regionBtn.classList.remove('active');
3335                regionWrap.classList.remove('active');
3336            }
3337        });
3338    }
3339  }
3340
3341
3342function checkWindowSize() {
3343    if($(window).width() > 1024){
3344        handleImageHover();
3345    }else {
3346        $('[data-over-image]').each(function () {
3347            let originUrl = $(this).find('img').attr('src');
3348            $(this).find('img').attr('src', originUrl);
3349            $(this).off('mouseenter mouseleave');
3350        });
3351    }
3352}
3353 
3354function handleImageHover() {
3355    // image hover script
3356    $('[data-over-image]').each(function () {
3357        let originUrl = $(this).find('img').attr('src');
3358        let hoverUrl = $(this).data('over-image');
3359
3360        $(this).on('mouseenter', function () {
3361            $(this).find('img').attr('src', hoverUrl);
3362        }).on('mouseleave', function () {
3363            $(this).find('img').attr('src', originUrl);
3364        });
3365    });
3366}
3367
3368// Tab Button Selected-State Title
3369$(function(){
3370    $(".ui-tab-btn.selected").attr("title","선택됨");
3371    $(".ui-tab-btn").on('click', function(){
3372        $(".ui-tab-btns").find("b").remove();
3373        $(this).attr("title","선택됨").siblings().attr("title", "");
3374    });
3375})
3376
3377// Popup Open Handler
3378function popOpen(target,id){
3379    $("#"+id).show().focus()
3380
3381    $(".pop-c").click(function(){
3382        $(this).closest(".nft_pop").hide();
3383        $(target).focus();
3384    })
3385}

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.