미디어위키:Gadget-Vector.js: 두 판 사이의 차이

식물 vs 좀비 위키
둘러보기로 이동 검색으로 이동
새 문서: ========================= MediaWiki:Gadget-core.js =========================: (function () { 'use strict'; document.documentElement.classList.add('pvz-desktop-booting'); var PVZ_SEARCH_TIMER = null; var PVZ_SEARCH_REQUEST_ID = 0; var PVZ_SELECTED_SUGGESTION = -1; var PVZ_SUGGESTIONS = []; var PVZ_LAST_SEARCH_QUERY = ''; function pvzReady(callback) { function run() { if (window.mw && mw.loader && mw.loader.using) { mw.loader.using('media...
태그: 모바일 편집 모바일 웹 편집
 
편집 요약 없음
태그: 수동 되돌리기
 
(같은 사용자의 중간 판 28개는 보이지 않습니다)
1번째 줄: 1번째 줄:
/* =========================
MediaWiki:Gadget-core.js
========================= */
(function () {
(function () {
  'use strict';
'use strict';


  document.documentElement.classList.add('pvz-desktop-booting');
var SPIN_CLASS = 'pvz-watch-spinning';
var WATCHED_CLASS = 'pvz-watch-watched';
var NOT_WATCHED_CLASS = 'pvz-watch-not-watched';
var SPIN_TIME = 360;
var cleanupTimer = 0;


  var PVZ_SEARCH_TIMER = null;
function getContainer() {
  var PVZ_SEARCH_REQUEST_ID = 0;
return document.querySelector(
  var PVZ_SELECTED_SUGGESTION = -1;
'#ca-watch, #ca-unwatch, li.mw-watchlink, a.mw-watchlink'
  var PVZ_SUGGESTIONS = [];
);
  var PVZ_LAST_SEARCH_QUERY = '';
}


  function pvzReady(callback) {
function getLink(container) {
    function run() {
if (!container) {
      if (window.mw && mw.loader && mw.loader.using) {
return null;
        mw.loader.using('mediawiki.util').then(callback, callback);
}
      } else {
        callback();
      }
    }


    if (document.readyState === 'loading') {
return container.matches('a') ? container : container.querySelector('a');
      document.addEventListener('DOMContentLoaded', run, { once: true });
}
    } else {
      run();
    }
  }


  function pvzArray(list) {
function applyState(isWatched) {
    return Array.prototype.slice.call(list || []);
var container = getContainer();
  }


  function pvzClosest(target, selector) {
if (!container) {
    if (!target) return null;
return;
    if (target.nodeType !== 1) target = target.parentElement;
}
    if (!target || typeof target.closest !== 'function') return null;
    return target.closest(selector);
  }


  function pvzText(node) {
container.classList.toggle(WATCHED_CLASS, !!isWatched);
    return node ? (node.textContent || '').replace(/\s+/g, ' ').trim() : '';
container.classList.toggle(NOT_WATCHED_CLASS, !isWatched);
  }
}


  function pvzRemoveById(id) {
function syncFromMarkup() {
    var el = document.getElementById(id);
var container = getContainer();
    if (el && el.parentNode) el.parentNode.removeChild(el);
var link = getLink(container);
  }
var href;


  function pvzGetUrl(title) {
if (!container || !link) {
    if (window.mw && mw.util && typeof mw.util.getUrl === 'function') {
return;
      return mw.util.getUrl(title);
}
    }


    return '/wiki/' + encodeURIComponent(String(title || '')).replace(/%20/g, '_');
href = link.getAttribute('href') || '';
  }


  function pvzGetApiUrl() {
applyState(
    if (window.mw && mw.util && typeof mw.util.wikiScript === 'function') {
container.id === 'ca-unwatch' ||
      return mw.util.wikiScript('api');
href.indexOf('action=unwatch') !== -1
    }
);
}


    if (window.mw && mw.config && mw.config.get('wgScriptPath')) {
function spin() {
      return mw.config.get('wgScriptPath') + '/api.php';
var container = getContainer();
    }


    return '/w/api.php';
if (!container) {
  }
return;
}


  function pvzGetPageName() {
window.clearTimeout(cleanupTimer);
    if (window.mw && mw.config && mw.config.get('wgPageName')) {
container.classList.remove(SPIN_CLASS);
      return mw.config.get('wgPageName');
void container.offsetWidth;
    }
container.classList.add(SPIN_CLASS);


    return (document.title || '').replace(/\s*-\s*.*$/, '').replace(/\s+/g, '_');
cleanupTimer = window.setTimeout(function () {
  }
container.classList.remove(SPIN_CLASS);
}, SPIN_TIME + 40);
}


  function pvzGetTitleText() {
function handleClick(event) {
    var heading = document.getElementById('firstHeading') ||
var link = event.target.closest(
      document.querySelector('.mw-first-heading, .firstHeading');
'#ca-watch > a, #ca-unwatch > a, li.mw-watchlink > a, a.mw-watchlink'
);


    if (heading) {
if (link) {
      return pvzText(heading);
spin();
    }
}
}


    if (window.mw && mw.config && mw.config.get('wgTitle')) {
function shortenHistoryLabel() {
      return mw.config.get('wgTitle');
var historyLink = document.querySelector('#ca-history > a');
    }


    return (document.title || '').replace(/\s*-\s*.*$/, '');
if (!historyLink) {
  }
return;
}


  function pvzGetTalkPageName() {
Array.prototype.forEach.call(historyLink.childNodes, function (node) {
    var pageName = pvzGetPageName();
if (node.nodeType === Node.TEXT_NODE) {
    var ns;
node.nodeValue = node.nodeValue.replace(/역사 보기/g, '역사');
    var title;
}
    var namespaces;
});
    var talkNamespace;


    if (window.mw && mw.config) {
if (historyLink.textContent.trim() === '역사 보기') {
      ns = mw.config.get('wgNamespaceNumber');
historyLink.textContent = '역사';
      title = mw.config.get('wgTitle');
}
      namespaces = mw.config.get('wgFormattedNamespaces');


      if (ns === -1 || ns % 2 === 1) return pageName;
historyLink.setAttribute('title', '역사');
}


      talkNamespace = namespaces && namespaces[ns + 1] ? namespaces[ns + 1] : 'Talk';
function init() {
var observer;


      if (ns === 0) {
shortenHistoryLabel();
        talkNamespace = namespaces && namespaces[1] ? namespaces[1] : 'Talk';
syncFromMarkup();
      }
document.addEventListener('click', handleClick, true);


      return talkNamespace + ':' + title;
observer = new MutationObserver(function () {
    }
shortenHistoryLabel();
syncFromMarkup();
});


    return 'Talk:' + pageName;
observer.observe(document.body, {
  }
subtree: true,
childList: true,
attributes: true,
attributeFilter: ['id', 'href']
});


  function pvzGetSearchUrl(query) {
if (window.mw && mw.hook) {
    var value = (query || '').replace(/\s+/g, ' ').trim();
mw.hook('wikipage.watchlistChange').add(function (isWatched) {
    if (!value) return pvzGetUrl('Special:Search');
applyState(isWatched);
    return pvzGetUrl('Special:Search') + '?search=' + encodeURIComponent(value) + '&fulltext=1';
spin();
  }
});
}
}


  function pvzSyncClasses() {
if (document.readyState === 'loading') {
    var root = document.documentElement;
document.addEventListener('DOMContentLoaded', init, { once: true });
    var body = document.body;
} else {
    var ua = navigator.userAgent || '';
init();
    var screenW = window.screen && window.screen.width ? window.screen.width : 9999;
}
    var screenH = window.screen && window.screen.height ? window.screen.height : 9999;
}());
    var hasTouch = !!(navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0);
    var nativeMobile = !!(body && body.classList && body.classList.contains('mw-mf'));
    var isVector = !!(body && body.classList && (
      body.classList.contains('skin-vector') ||
      body.classList.contains('skin-vector-2022')
    ));
    var touchDevice = !!(
      /Android|iPhone|iPad|iPod|Mobile|Windows Phone/i.test(ua) ||
      (hasTouch && Math.min(screenW, screenH) <= 1400)
    );


    root.classList.toggle('pvz-skin-vector', isVector);
    root.classList.toggle('pvz-native-mobile', nativeMobile);
    root.classList.toggle('pvz-native-desktop', !nativeMobile);
    root.classList.toggle('pvz-touch-device', touchDevice);
    root.classList.toggle('pvz-desktop-view-on-touch', touchDevice && !nativeMobile);


    if (body) {
(function () {
      body.classList.toggle('pvz-vector-ready', isVector);
'use strict';
    }
  }


function installSearchButtonIcon(wrapper) {
var simpleSearch;
var searchButton;
var icon;


  function pvzCreateIcon(iconClass) {
if (!wrapper) {
    var span = document.createElement('span');
return;
    span.className = 'pvz-icon ' + iconClass;
}
    span.setAttribute('aria-hidden', 'true');
    return span;
  }


  function pvzSetIconOnly(el, iconClass) {
simpleSearch = wrapper.querySelector('#simpleSearch');
    el.textContent = '';
    el.appendChild(pvzCreateIcon(iconClass));
  }


  function pvzAppendIconText(parent, iconClass, label) {
if (!simpleSearch) {
    var text = document.createElement('span');
return;
    parent.appendChild(pvzCreateIcon(iconClass));
}
    text.textContent = label;
    parent.appendChild(text);
  }


  function pvzSetBoardButtonContent(parent, iconClass, label) {
searchButton =
    var text = document.createElement('span');
simpleSearch.querySelector('#searchButton') ||
simpleSearch.querySelector('.searchButton:not(#mw-searchButton)');


    parent.textContent = '';
if (!searchButton) {
return;
}


    if (iconClass) {
searchButton.classList.add('pvz-primary-search-button');
      parent.appendChild(pvzCreateIcon(iconClass));
    }


    text.className = 'pvz-board-btn-text';
icon = simpleSearch.querySelector('.pvz-search-button-icon');
    text.textContent = label;
    parent.appendChild(text);
  }


  function pvzPortletLink(ids) {
if (!icon) {
    var i;
icon = document.createElement('span');
    var link;
icon.className = 'pvz-search-button-icon';
icon.setAttribute('aria-hidden', 'true');
simpleSearch.appendChild(icon);
}
}


    for (i = 0; i < ids.length; i += 1) {
function installTopSearch() {
      link = document.querySelector('#' + ids[i] + ' a');
var content = document.querySelector('.skin-vector-legacy #content');
      if (link && link.href) return link;
var form = document.querySelector('#searchform');
    }
var wrapper;


    return null;
if (!content || !form || !document.body) {
  }
return;
}


  function pvzCloneAction(ids, label, className, iconClass) {
wrapper = document.getElementById('pvz-content-search');
    var source = pvzPortletLink(ids);
    var link;
    var action;
    var ns;
    var displayLabel;


    if (!source) return null;
if (!wrapper) {
wrapper = document.createElement('div');
wrapper.id = 'pvz-content-search';
wrapper.setAttribute('role', 'search');
wrapper.setAttribute('aria-label', '사이트 검색');
}


    displayLabel = label || pvzText(source);
if (wrapper.parentNode !== document.body) {
document.body.insertBefore(wrapper, content);
}


    link = document.createElement('a');
if (form.parentNode !== wrapper) {
    link.className = className || 'pvz-board-btn';
wrapper.appendChild(form);
    link.href = source.href;
}
    pvzSetBoardButtonContent(link, iconClass, displayLabel);


    if (source.getAttribute('title')) {
installSearchButtonIcon(wrapper);
      link.title = source.getAttribute('title');
document.documentElement.classList.add('pvz-content-search-ready');
    }
}


    if (source.classList.contains('new') || source.closest('.new')) {
function initTopSearch() {
      link.classList.add('new');
var observer;
    }


    if (source.closest('.selected') || source.closest('.mw-list-item.selected')) {
installTopSearch();
      link.classList.add('is-current');
    }


    if (window.mw && mw.config) {
observer = new MutationObserver(function () {
      action = mw.config.get('wgAction') || 'view';
installTopSearch();
      ns = mw.config.get('wgNamespaceNumber');
});


      if (
observer.observe(document.body, {
        action === 'view' &&
childList: true,
        ids.some(function (id) { return id === 'ca-view' || id === 'ca-nstab-main' || id === 'ca-nstab-project'; }) &&
subtree: true
        !(typeof ns === 'number' && ns % 2 === 1)
});
      ) {
}
        link.classList.add('is-current');
      }


      if (
if (document.readyState === 'loading') {
        typeof ns === 'number' &&
document.addEventListener('DOMContentLoaded', initTopSearch, { once: true });
        ns % 2 === 1 &&
} else {
        ids.some(function (id) { return id === 'ca-talk'; })
initTopSearch();
      ) {
}
        link.classList.add('is-current');
}());
      }


      if (
        (action === 'edit' || action === 'submit' || action === 'visualeditor') &&
        ids.some(function (id) { return id === 'ca-edit' || id === 'ca-ve-edit' || id === 'ca-viewsource'; })
      ) {
        link.classList.add('is-current');
      }


      if (
(function () {
        action === 'history' &&
'use strict';
        ids.some(function (id) { return id === 'ca-history'; })
      ) {
        link.classList.add('is-current');
      }
    }


    return link;
function syncSearchLeft() {
  }
var content = document.querySelector('.skin-vector-legacy #content');
var left;


  function pvzAppendIf(parent, child) {
if (!content) {
    if (child) parent.appendChild(child);
return;
  }
}


  function pvzCreateBoardHead() {
left = content.getBoundingClientRect().left + window.scrollX;
    var head = document.createElement('div');
document.documentElement.style.setProperty('--pvz-content-left', left + 'px');
    var left = document.createElement('div');
}
    var title = document.createElement('div');
    var tabs = document.createElement('div');
    var actions = document.createElement('div');
    var moreMap;
    var moreLinks;


    head.className = 'pvz-board-head';
function initSearchAlignment() {
    left.className = 'pvz-board-head-left';
syncSearchLeft();
    title.className = 'pvz-board-title-ribbon';
window.addEventListener('resize', syncSearchLeft, { passive: true });
    tabs.className = 'pvz-board-tabs';
window.addEventListener('orientationchange', syncSearchLeft, { passive: true });
    actions.className = 'pvz-board-actions';
}


    title.textContent = pvzGetTitleText();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSearchAlignment, { once: true });
} else {
initSearchAlignment();
}
}());


    var viewLink = pvzCloneAction(['ca-view', 'ca-nstab-main', 'ca-nstab-project'], '문서', null, 'pvz-icon-special');
    var talkLink = pvzCloneAction(['ca-talk'], '토론', null, 'pvz-icon-talk');
    if (viewLink) viewLink.classList.add('is-tab');
    if (talkLink) talkLink.classList.add('is-tab');


    pvzAppendIf(tabs, viewLink);
(function () {
    pvzAppendIf(tabs, talkLink);
'use strict';


    pvzAppendIf(actions, pvzCloneAction(['ca-edit', 'ca-ve-edit', 'ca-viewsource'], '편집', null, 'pvz-icon-tools'));
function removeObsoleteInterface() {
    pvzAppendIf(actions, pvzCloneAction(['ca-history'], '역사', null, 'pvz-icon-recent'));
var ids = [
    pvzAppendIf(actions, pvzCloneAction(['ca-watch'], '즐겨찾기에 추가', null, 'pvz-icon-star'));
'pvz-related-toggle',
    pvzAppendIf(actions, pvzCloneAction(['ca-unwatch'], '즐겨찾기 해제', null, 'pvz-icon-star'));
'pvz-related-menu',
'pvz-right-panel',
'pvz-left-panel-toggle',
'pvz-right-panel-toggle'
];


    moreMap = [
ids.forEach(function (id) {
      { ids: ['ca-move'], label: '이동', icon: 'pvz-icon-special' },
var element = document.getElementById(id);
      { ids: ['ca-purge'], label: '새로고침', icon: 'pvz-icon-recent' },
      { ids: ['ca-delete'], label: '삭제', icon: 'pvz-icon-tools' },
      { ids: ['ca-protect'], label: '보호', icon: 'pvz-icon-permissions' },
      { ids: ['ca-unprotect'], label: '보호 해제', icon: 'pvz-icon-permissions' }
    ];


    moreLinks = moreMap.map(function (item) {
if (element) {
      return pvzCloneAction(item.ids, item.label, null, item.icon);
element.remove();
    }).filter(Boolean);
}
});
}


    if (moreLinks.length) {
function restoreLogoToPanel(panel) {
      var details = document.createElement('details');
var wrapper = document.getElementById('pvz-sidebar-logo');
      var summary = document.createElement('summary');
var logo =
      var menu = document.createElement('div');
(wrapper && wrapper.querySelector('#p-logo')) ||
      var moreHasCurrent = moreLinks.some(function (link) {
document.querySelector('#p-logo');
        return link && link.classList && link.classList.contains('is-current');
      });
      details.className = 'pvz-board-more';
      pvzSetBoardButtonContent(summary, 'pvz-icon-plus', '더보기');
      if (moreHasCurrent) summary.classList.add('is-current');
      menu.className = 'pvz-board-more-menu';
      moreLinks.forEach(function (link) { menu.appendChild(link); });
      details.appendChild(summary);
      details.appendChild(menu);
      actions.appendChild(details);
    }


    left.appendChild(title);
if (!panel || !logo) {
    left.appendChild(tabs);
return;
    head.appendChild(left);
}
    head.appendChild(actions);
    return head;
  }


  function pvzGetActiveSearchInput() {
if (logo.parentNode !== panel) {
    return document.getElementById('pvz-desktop-search-input') ||
panel.insertBefore(logo, panel.firstChild);
      document.getElementById('pvz-mobile-search-input');
}
  }


  function pvzCreateSearchPanel() {
if (wrapper) {
    var old = document.getElementById('pvz-search-suggestions');
wrapper.remove();
    var panel;
}
}


    if (old) return old;
function syncPanelTop() {
var content = document.querySelector('.skin-vector-legacy #content');
var top;


    panel = document.createElement('div');
if (!content) {
    panel.id = 'pvz-search-suggestions';
return;
    panel.className = 'pvz-search-suggestions';
}
    panel.setAttribute('aria-label', '검색어 추천');


    document.body.appendChild(panel);
top = content.getBoundingClientRect().top + window.scrollY;
    return panel;
document.documentElement.style.setProperty('--pvz-content-top', top + 'px');
  }
}


  function pvzCloseSuggestions() {
function syncSearchLeft() {
    document.documentElement.classList.remove('pvz-suggestions-open');
var content = document.querySelector('.skin-vector-legacy #content');
    PVZ_SELECTED_SUGGESTION = -1;
var left;
  }


  function pvzPositionSearchPanel() {
if (!content) {
    var panel = document.getElementById('pvz-search-suggestions');
return;
    var input = pvzGetActiveSearchInput();
}
    var rect;
    var left;
    var top;
    var width;


    if (!panel || !input || typeof input.getBoundingClientRect !== 'function') return;
left = content.getBoundingClientRect().left + window.scrollX;
document.documentElement.style.setProperty('--pvz-content-left', left + 'px');
}


    rect = input.getBoundingClientRect();
function installV27Interface() {
    left = Math.max(8, rect.left);
var panel = document.querySelector('.skin-vector-legacy #mw-panel');
    top = rect.bottom + 6;
    width = Math.min(rect.width, window.innerWidth - 16);


    panel.style.setProperty('left', left + 'px', 'important');
removeObsoleteInterface();
    panel.style.setProperty('top', top + 'px', 'important');
restoreLogoToPanel(panel);
    panel.style.setProperty('width', width + 'px', 'important');
syncPanelTop();
  }
syncSearchLeft();
}


  function pvzOpenSuggestions() {
function initV27Interface() {
    pvzPositionSearchPanel();
installV27Interface();
    if (PVZ_SUGGESTIONS.length) {
      document.documentElement.classList.add('pvz-suggestions-open');
    }
  }


  function pvzEscapeRegExp(text) {
window.addEventListener('resize', function () {
    return String(text || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
syncPanelTop();
  }
syncSearchLeft();
}, { passive: true });


  function pvzAppendHighlightedTitle(container, text, query) {
window.addEventListener('orientationchange', function () {
    var value = text || '';
syncPanelTop();
    var keyword = (query || '').replace(/\s+/g, ' ').trim();
syncSearchLeft();
    var regex;
}, { passive: true });
    var lastIndex = 0;
}
    var match;


    container.textContent = '';
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initV27Interface, { once: true });
} else {
initV27Interface();
}
}());


    if (!keyword) {
      container.textContent = value;
      return;
    }


    regex = new RegExp(pvzEscapeRegExp(keyword), 'ig');
(function () {
'use strict';


    while ((match = regex.exec(value)) !== null) {
function installGrassDividers(root) {
      if (match.index > lastIndex) {
var scope = root || document;
        var normal = document.createElement('span');
var wrappers;
        normal.className = 'pvz-search-suggestion-normal';
var legacyHeadings;
        normal.textContent = value.slice(lastIndex, match.index);
        container.appendChild(normal);
      }


      var strong = document.createElement('strong');
wrappers = scope.querySelectorAll(
      strong.className = 'pvz-search-suggestion-match';
'.skin-vector-legacy .mw-parser-output .mw-heading2'
      strong.textContent = value.slice(match.index, match.index + match[0].length);
);
      container.appendChild(strong);


      lastIndex = match.index + match[0].length;
Array.prototype.forEach.call(wrappers, function (wrapper) {
    }
var divider;


    if (lastIndex === 0) {
wrapper.classList.add('pvz-grass-heading');
      container.textContent = value;
      return;
    }


    if (lastIndex < value.length) {
divider = wrapper.querySelector(
      var tail = document.createElement('span');
':scope > .pvz-grass-divider'
      tail.className = 'pvz-search-suggestion-normal';
);
      tail.textContent = value.slice(lastIndex);
      container.appendChild(tail);
    }
  }


  function pvzRenderSearchSuggestions(items) {
if (!divider) {
    var panel = pvzCreateSearchPanel();
divider = document.createElement('span');
    var list = document.createElement('ul');
divider.className = 'pvz-grass-divider';
divider.setAttribute('aria-hidden', 'true');
wrapper.appendChild(divider);
}
});


    panel.innerHTML = '';
legacyHeadings = scope.querySelectorAll(
    PVZ_SELECTED_SUGGESTION = -1;
'.skin-vector-legacy .mw-parser-output > h2'
);


    if (!items.length) {
Array.prototype.forEach.call(legacyHeadings, function (heading) {
      pvzCloseSuggestions();
var divider;
      return;
    }


    list.className = 'pvz-search-suggestions-list';
if (heading.closest('.mw-heading2')) {
return;
}


    items.forEach(function (item, index) {
heading.classList.add('pvz-grass-heading');
      var li = document.createElement('li');
      var a = document.createElement('a');
      var thumb = document.createElement('span');
      var title = document.createElement('span');


      li.className = 'pvz-search-suggestion';
divider = heading.querySelector(
      li.setAttribute('data-pvz-suggestion-index', String(index));
':scope > .pvz-grass-divider'
);


      a.className = 'pvz-search-suggestion-link';
if (!divider) {
      a.href = item.href;
divider = document.createElement('span');
divider.className = 'pvz-grass-divider';
divider.setAttribute('aria-hidden', 'true');
heading.appendChild(divider);
}
});
}


      thumb.className = 'pvz-search-suggestion-thumb';
function initGrassDividers() {
var observer;


      if (item.thumbnail) {
installGrassDividers(document);
        var img = document.createElement('img');
        thumb.classList.add('has-image');
        img.src = item.thumbnail;
        img.alt = '';
        img.loading = 'lazy';
        thumb.appendChild(img);
      } else {
        thumb.classList.add('is-empty');
      }


      title.className = 'pvz-search-suggestion-title';
observer = new MutationObserver(function (mutations) {
      pvzAppendHighlightedTitle(title, item.title, PVZ_LAST_SEARCH_QUERY);
mutations.forEach(function (mutation) {
Array.prototype.forEach.call(
mutation.addedNodes,
function (node) {
if (node.nodeType !== Node.ELEMENT_NODE) {
return;
}


      a.appendChild(thumb);
if (
      a.appendChild(title);
node.matches(
      a.addEventListener('click', pvzCloseSuggestions);
'.mw-heading2, .mw-parser-output > h2'
)
) {
installGrassDividers(node.parentNode);
return;
}


      li.appendChild(a);
installGrassDividers(node);
      list.appendChild(li);
}
    });
);
});
});


    panel.appendChild(list);
observer.observe(document.body, {
    pvzOpenSuggestions();
childList: true,
  }
subtree: true
});
}


  function pvzFetchSearchSuggestions(query) {
if (document.readyState === 'loading') {
    var value = (query || '').replace(/\s+/g, ' ').trim();
document.addEventListener(
    var requestId;
'DOMContentLoaded',
    var url;
initGrassDividers,
{ once: true }
);
} else {
initGrassDividers();
}
}());


    if (!value || !window.fetch) {
      PVZ_LAST_SEARCH_QUERY = '';
      PVZ_SUGGESTIONS = [];
      pvzRenderSearchSuggestions([]);
      pvzCloseSuggestions();
      return;
    }


    PVZ_LAST_SEARCH_QUERY = value;
(function () {
    requestId = ++PVZ_SEARCH_REQUEST_ID;
'use strict';
 
    url =
      pvzGetApiUrl() +
      '?action=query' +
      '&format=json' +
      '&formatversion=2' +
      '&generator=prefixsearch' +
      '&gpsnamespace=0' +
      '&gpslimit=8' +
      '&gpssearch=' + encodeURIComponent(value) +
      '&prop=pageimages' +
      '&piprop=thumbnail' +
      '&pithumbsize=72' +
      '&pilimit=8' +
      '&redirects=1';
 
    fetch(url, { credentials: 'same-origin' })
      .then(function (res) { return res.json(); })
      .then(function (data) {
        var pages;
 
        if (requestId !== PVZ_SEARCH_REQUEST_ID) return;
 
        pages = data && data.query && Array.isArray(data.query.pages)
          ? data.query.pages
          : [];
 
        pages.sort(function (a, b) {
          return (a.index || 9999) - (b.index || 9999);
        });
 
        PVZ_SUGGESTIONS = pages.map(function (page) {
          return {
            title: page.title,
            href: pvzGetUrl(page.title),
            thumbnail: page.thumbnail && page.thumbnail.source ? page.thumbnail.source : ''
          };
        });
 
        pvzRenderSearchSuggestions(PVZ_SUGGESTIONS);
      })
      .catch(function () {
        if (requestId === PVZ_SEARCH_REQUEST_ID) {
          PVZ_SUGGESTIONS = [];
          pvzRenderSearchSuggestions([]);
          pvzCloseSuggestions();
        }
      });
  }
 
  function pvzScheduleSearchSuggestions(query) {
    window.clearTimeout(PVZ_SEARCH_TIMER);
    PVZ_SEARCH_TIMER = window.setTimeout(function () {
      pvzFetchSearchSuggestions(query);
    }, 140);
  }
 
  function pvzUpdateSelectedSuggestion() {
    document.querySelectorAll('.pvz-search-suggestion').forEach(function (li) {
      var index = parseInt(li.getAttribute('data-pvz-suggestion-index'), 10);
      li.classList.toggle('is-selected', index === PVZ_SELECTED_SUGGESTION);
    });
  }
 
  function pvzHandleSearchKeydown(event) {
    var input = pvzGetActiveSearchInput();
    var item;
 
    if (event.key === 'ArrowDown') {
      if (!PVZ_SUGGESTIONS.length) return;
      event.preventDefault();
      PVZ_SELECTED_SUGGESTION += 1;
      if (PVZ_SELECTED_SUGGESTION >= PVZ_SUGGESTIONS.length) PVZ_SELECTED_SUGGESTION = 0;
      pvzUpdateSelectedSuggestion();
      return;
    }
 
    if (event.key === 'ArrowUp') {
      if (!PVZ_SUGGESTIONS.length) return;
      event.preventDefault();
      PVZ_SELECTED_SUGGESTION -= 1;
      if (PVZ_SELECTED_SUGGESTION < 0) PVZ_SELECTED_SUGGESTION = PVZ_SUGGESTIONS.length - 1;
      pvzUpdateSelectedSuggestion();
      return;
    }
 
    if (event.key === 'Enter') {
      if (PVZ_SELECTED_SUGGESTION >= 0 && PVZ_SUGGESTIONS[PVZ_SELECTED_SUGGESTION]) {
        event.preventDefault();
        item = PVZ_SUGGESTIONS[PVZ_SELECTED_SUGGESTION];
        window.location.href = item.href;
        return;
      }
 
      if (input && input.value.replace(/\s+/g, ' ').trim()) {
        event.preventDefault();
        window.location.href = pvzGetSearchUrl(input.value);
      }
 
      return;
    }
 
    if (event.key === 'Escape') {
      event.preventDefault();
      pvzCloseSuggestions();
    }
  }
 
  function pvzGetLocal(key, fallback) {
    try {
      return localStorage.getItem(key) || fallback;
    } catch (e) {
      return fallback;
    }
  }
 
  function pvzSetLocal(key, value) {
    try {
      localStorage.setItem(key, value);
    } catch (e) {}
  }
 
  function pvzSetFontSize(value) {
    if (value !== 'small' && value !== 'medium' && value !== 'large') value = 'small';
    pvzSetLocal('pvz-font-size', value);
    document.documentElement.classList.remove('pvz-font-small', 'pvz-font-medium', 'pvz-font-large');
    document.documentElement.classList.add('pvz-font-' + value);
    pvzUpdateChoices();
  }
 
  function pvzSetTheme(value) {
    if (value !== 'auto' && value !== 'light' && value !== 'dark') value = 'auto';
    pvzSetLocal('pvz-mobile-theme', value);
    document.documentElement.classList.remove('pvz-theme-auto', 'pvz-theme-light', 'pvz-theme-dark');
    document.documentElement.classList.add('pvz-theme-' + value);
    pvzUpdateChoices();
  }
 
  function pvzSetWidth(value) {
    if (value !== 'normal' && value !== 'wide') value = 'normal';
    pvzSetLocal('pvz-mobile-width', value);
    document.documentElement.classList.remove('pvz-width-normal', 'pvz-width-wide', 'pvz-width-full');
    document.documentElement.classList.add('pvz-width-' + value);
    pvzUpdateChoices();
  }
 
  function pvzSetAutoHide(value) {
    if (value !== 'on' && value !== 'off') value = 'off';
    pvzSetLocal('pvz-mobile-autohide', value);
    document.documentElement.classList.remove('pvz-auto-hide-on', 'pvz-auto-hide-off');
    document.documentElement.classList.add('pvz-auto-hide-' + value);
    pvzUpdateChoices();
  }
 
  function pvzSetPerformance(value) {
    if (value !== 'on' && value !== 'off') value = 'off';
    pvzSetLocal('pvz-mobile-performance', value);
    document.documentElement.classList.remove('pvz-performance-on', 'pvz-performance-off');
    document.documentElement.classList.add('pvz-performance-' + value);
    pvzUpdateChoices();
  }
 
  function pvzApplyPreferences() {
    pvzSetFontSize(pvzGetLocal('pvz-font-size', 'small'));
    pvzSetTheme(pvzGetLocal('pvz-mobile-theme', 'auto'));
    pvzSetWidth(pvzGetLocal('pvz-mobile-width', 'normal'));
    pvzSetAutoHide(pvzGetLocal('pvz-mobile-autohide', 'off'));
    pvzSetPerformance(pvzGetLocal('pvz-mobile-performance', 'off'));
  }
 
  function pvzUpdateChoices() {
    var values = {
      font: pvzGetLocal('pvz-font-size', 'small'),
      theme: pvzGetLocal('pvz-mobile-theme', 'auto'),
      width: pvzGetLocal('pvz-mobile-width', 'normal'),
      autohide: pvzGetLocal('pvz-mobile-autohide', 'off'),
      performance: pvzGetLocal('pvz-mobile-performance', 'off')
    };
 
    document.querySelectorAll('.pvz-mobile-choice').forEach(function (button) {
      var kind = button.getAttribute('data-pvz-setting-kind');
      var value = button.getAttribute('data-pvz-setting-value');
      button.classList.toggle('is-selected', values[kind] === value);
    });
  }
 
  function pvzCreateMobileLink(iconClass, label, href) {
    var li = document.createElement('li');
    var a = document.createElement('a');
 
    a.href = href;
    pvzAppendIconText(a, iconClass, label);
 
    li.appendChild(a);
    return li;
  }
 
  function pvzCreateMobileLinkList(items) {
    var ul = document.createElement('ul');
 
    ul.className = 'pvz-mobile-link-list';
 
    items.forEach(function (item) {
      ul.appendChild(pvzCreateMobileLink(item.icon, item.label, item.href));
    });
 
    return ul;
  }
 
  function pvzCreateSheetSection(title, content) {
    var section = document.createElement('section');
    var h = document.createElement('div');
 
    section.className = 'pvz-mobile-sheet-section';
    h.className = 'pvz-mobile-sheet-section-title';
    h.textContent = title;
 
    section.appendChild(h);
    section.appendChild(content);
 
    return section;
  }
 
  function pvzCreateBrowsePanel() {
    var panel = document.createElement('nav');
 
    panel.id = 'pvz-mobile-panel-browse';
    panel.className = 'pvz-mobile-sheet pvz-mobile-sheet-left';
    panel.setAttribute('aria-label', '둘러보기');
 
    panel.appendChild(pvzCreateSheetSection('둘러보기', pvzCreateMobileLinkList([
      { icon: 'pvz-icon-home', label: '대문', href: pvzGetUrl('대문') },
      { icon: 'pvz-icon-recent', label: '최근 바뀜', href: pvzGetUrl('Special:RecentChanges') },
      { icon: 'pvz-icon-random', label: '임의 문서로', href: pvzGetUrl('Special:Random') },
      { icon: 'pvz-icon-help', label: '미디어위키 도움말', href: pvzGetUrl('Help:Contents') },
      { icon: 'pvz-icon-special', label: '특수 문서 목록', href: pvzGetUrl('Special:SpecialPages') },
      { icon: 'pvz-icon-upload', label: '파일 올리기', href: pvzGetUrl('Special:Upload') }
    ])));
 
    panel.appendChild(pvzCreateSheetSection('관리', pvzCreateMobileLinkList([
      { icon: 'pvz-icon-settings', label: '이 위키의 핵심 설정을 관리하기', href: pvzGetUrl('Special:ManageWiki/settings') },
      { icon: 'pvz-icon-extensions', label: '이 위키의 확장 기능을 관리하기', href: pvzGetUrl('Special:ManageWiki/extensions') },
      { icon: 'pvz-icon-namespace', label: '이 위키의 이름공간 관리', href: pvzGetUrl('Special:ManageWiki/namespaces') },
      { icon: 'pvz-icon-permissions', label: '이 위키의 권한 관리', href: pvzGetUrl('Special:ManageWiki/permissions') },
      { icon: 'pvz-icon-plus', label: '이 위키의 추가 설정을 관리하기', href: pvzGetUrl('Special:ManageWiki/settings') },
      { icon: 'pvz-icon-backup', label: '이 위키의 백업을 관리', href: pvzGetUrl('Special:DataDump') }
    ])));
 
    return panel;
  }
 
  function pvzCreateChoice(label, kind, value, extraClass) {
    var button = document.createElement('button');
 
    button.type = 'button';
    button.className = 'pvz-mobile-choice' + (extraClass ? ' ' + extraClass : '');
    button.setAttribute('data-pvz-setting-kind', kind);
    button.setAttribute('data-pvz-setting-value', value);
    button.textContent = label;
 
    button.addEventListener('click', function (event) {
      event.preventDefault();
 
      if (kind === 'font') pvzSetFontSize(value);
      if (kind === 'theme') pvzSetTheme(value);
      if (kind === 'width') pvzSetWidth(value);
      if (kind === 'autohide') pvzSetAutoHide(value);
      if (kind === 'performance') pvzSetPerformance(value);
    });
 
    return button;
  }
 
  function pvzCreateChoiceGroup(title, kind, choices, gridClass) {
    var wrap = document.createElement('div');
    var h = document.createElement('div');
    var grid = document.createElement('div');
 
    wrap.className = 'pvz-mobile-setting-group';
    h.className = 'pvz-mobile-setting-title';
    h.textContent = title;
    grid.className = 'pvz-mobile-choice-grid' + (gridClass ? ' ' + gridClass : '');
 
    choices.forEach(function (choice) {
      grid.appendChild(pvzCreateChoice(choice.label, kind, choice.value, choice.extraClass));
    });
 
    wrap.appendChild(h);
    wrap.appendChild(grid);
 
    return wrap;
  }
 
  function pvzCreateSettingsPanel() {
    var panel = document.createElement('section');
 
    panel.id = 'pvz-mobile-panel-settings';
    panel.className = 'pvz-mobile-sheet pvz-mobile-sheet-right';
    panel.setAttribute('aria-label', '화면 설정');
 
    panel.appendChild(pvzCreateChoiceGroup('글자 크기', 'font', [
      { label: '작게', value: 'small' },
      { label: '보통', value: 'medium' },
      { label: '크게', value: 'large' }
    ], 'three'));
 
    panel.appendChild(pvzCreateChoiceGroup('색상 테마', 'theme', [
      { label: '자동', value: 'auto' },
      { label: '라이트', value: 'light' },
      { label: '다크', value: 'dark', extraClass: 'dark' }
    ], 'three'));
 
    panel.appendChild(pvzCreateChoiceGroup('페이지 너비', 'width', [
      { label: '기본', value: 'normal' },
      { label: '넓게', value: 'wide' }
    ], ''));
 
    panel.appendChild(pvzCreateChoiceGroup('자동으로 메뉴 숨김', 'autohide', [
      { label: '끄기', value: 'off' },
      { label: '켜기', value: 'on' }
    ], ''));
 
    panel.appendChild(pvzCreateChoiceGroup('Performance mode', 'performance', [
      { label: 'Off', value: 'off' },
      { label: 'On', value: 'on' }
    ], ''));
 
    return panel;
  }
 
  function pvzFormatUserGroup(group) {
    var map = {
      bureaucrat: '사무관',
      sysop: '관리자',
      administrator: '관리자',
      interfaceadmin: '인터페이스 관리자',
      'interface-admin': '인터페이스 관리자',
      bot: '봇',
      autoconfirmed: '자동 인증된 사용자',
      user: '사용자'
    };
 
    return map[group] || group;
  }
 
  function pvzFormatDate(value) {
    var date;
    var days = ['일', '월', '화', '수', '목', '금', '토'];
 
    if (!value) return '확인 불가';
 
    date = new Date(value);
    if (isNaN(date.getTime())) return '확인 불가';
 
    return date.getFullYear() + '년 ' + (date.getMonth() + 1) + '월 ' +
      date.getDate() + '일 (' + days[date.getDay()] + ')';
  }
 
  function pvzCreateAccountPanel() {
    var panel = document.createElement('section');
    var username = window.mw && mw.config ? mw.config.get('wgUserName') : null;
    var card = document.createElement('div');
    var name = document.createElement('div');
    var groups = document.createElement('div');
    var stats = document.createElement('div');
 
    panel.id = 'pvz-mobile-panel-account';
    panel.className = 'pvz-mobile-sheet pvz-mobile-sheet-right';
    panel.setAttribute('aria-label', '계정');
 
    card.className = 'pvz-mobile-account-card';
 
    name.id = 'pvz-mobile-account-name';
    name.className = 'pvz-mobile-account-name';
    name.textContent = username || '로그인하지 않음';
 
    groups.id = 'pvz-mobile-account-groups';
    groups.className = 'pvz-mobile-account-groups';
    groups.textContent = username ? '계정 정보를 불러오는 중...' : '비로그인 사용자';
 
    stats.className = 'pvz-mobile-account-stats';
    stats.innerHTML =
      '<span>편집</span><span>가입일</span>' +
      '<strong id="pvz-mobile-account-edits">-</strong>' +
      '<strong id="pvz-mobile-account-registration">-</strong>';
 
    card.appendChild(name);
    card.appendChild(groups);
    card.appendChild(stats);
    panel.appendChild(card);
 
    if (!username) {
      panel.appendChild(pvzCreateSheetSection('계정', pvzCreateMobileLinkList([
        { icon: 'pvz-icon-login', label: '로그인', href: pvzGetUrl('Special:UserLogin') },
        { icon: 'pvz-icon-plus', label: '회원 가입', href: pvzGetUrl('Special:CreateAccount') }
      ])));
 
      return panel;
    }
 
    panel.appendChild(pvzCreateMobileLinkList([
      { icon: 'pvz-icon-talk', label: '토론', href: pvzGetUrl('User talk:' + username) },
      { icon: 'pvz-icon-star', label: '즐겨찾기 문서', href: pvzGetUrl('Special:Watchlist') },
      { icon: 'pvz-icon-recent', label: '기여', href: pvzGetUrl('Special:Contributions/' + username) }
    ]));
 
    var logout = document.createElement('a');
    logout.className = 'pvz-mobile-account-logout';
    logout.href = pvzGetUrl('Special:UserLogout');
    pvzAppendIconText(logout, 'pvz-icon-login', '로그아웃');
    panel.appendChild(logout);
 
    return panel;
  }
 
  function pvzLoadAccountInfo() {
    var username = window.mw && mw.config ? mw.config.get('wgUserName') : null;
    var url;
 
    if (!username || !window.fetch) return;
 
    url =
      pvzGetApiUrl() +
      '?action=query' +
      '&format=json' +
      '&list=users' +
      '&usprop=groups%7Ceditcount%7Cregistration' +
      '&ususers=' + encodeURIComponent(username);
 
    fetch(url, { credentials: 'same-origin' })
      .then(function (res) { return res.json(); })
      .then(function (data) {
        var user = data && data.query && data.query.users && data.query.users[0];
        var groupBox = document.getElementById('pvz-mobile-account-groups');
        var editBox = document.getElementById('pvz-mobile-account-edits');
        var regBox = document.getElementById('pvz-mobile-account-registration');
 
        if (!user) return;
 
        if (groupBox) {
          groupBox.textContent = (user.groups || [])
            .filter(function (group) {
              return group !== '*' && group !== 'user' && group !== 'autoconfirmed';
            })
            .map(pvzFormatUserGroup)
            .join('  ') || '일반 사용자';
        }
 
        if (editBox) {
          editBox.textContent = typeof user.editcount === 'number' ? String(user.editcount) : '-';
        }
 
        if (regBox) {
          regBox.textContent = pvzFormatDate(user.registration);
        }
      })
      .catch(function () {});
  }
 
  function pvzCreatePanels() {
    var backdrop;
 
    pvzRemoveById('pvz-mobile-panel-backdrop');
    pvzRemoveById('pvz-mobile-panel-browse');
    pvzRemoveById('pvz-mobile-panel-settings');
    pvzRemoveById('pvz-mobile-panel-account');
 
    backdrop = document.createElement('div');
    backdrop.id = 'pvz-mobile-panel-backdrop';
    backdrop.className = 'pvz-mobile-panel-backdrop';
 
    document.body.appendChild(backdrop);
    document.body.appendChild(pvzCreateBrowsePanel());
    document.body.appendChild(pvzCreateSettingsPanel());
    document.body.appendChild(pvzCreateAccountPanel());
 
    pvzUpdateChoices();
  }
 
  function pvzClosePanels() {
    document.documentElement.classList.remove('pvz-mobile-panel-open');
 
    document.querySelectorAll('.pvz-mobile-sheet').forEach(function (panel) {
      panel.classList.remove('is-open');
    });
 
    document.querySelectorAll('.pvz-mobile-nav-button').forEach(function (button) {
      button.classList.remove('is-active');
    });
  }
 
  function pvzOpenPanel(name) {
    var panel = document.getElementById('pvz-mobile-panel-' + name);
 
    if (!panel) return;
 
    pvzCloseSuggestions();
    pvzClosePanels();
 
    document.documentElement.classList.add('pvz-mobile-panel-open');
    panel.classList.add('is-open');
 
    document.querySelectorAll('.pvz-mobile-nav-button').forEach(function (button) {
      button.classList.toggle('is-active', button.getAttribute('data-pvz-mobile-panel') === name);
    });
 
    if (name === 'account') pvzLoadAccountInfo();
    pvzUpdateChoices();
  }
 
  function pvzTogglePanel(name) {
    var panel = document.getElementById('pvz-mobile-panel-' + name);
 
    if (panel && panel.classList.contains('is-open')) {
      pvzClosePanels();
      return;
    }
 
    pvzOpenPanel(name);
  }
 
  function pvzCleanupOldBars() {
    document.querySelectorAll(
      '#pvz-appbar, .pvz-appbar, #pvz-pc-accountbar, .pvz-pc-accountbar, ' +
      '#pvz-pc-side-settings-button, .pvz-pc-side-settings-button, .pvz-restored-topbar, ' +
      '#pvz-mobile-topbar, .pvz-mobile-topbar, .pvz-timeless-custom-topbar, ' +
      '.pvz-timeless-custom-search-form, .pvz-timeless-custom-search-input'
    ).forEach(function (el) {
      if (el && el.parentNode) el.parentNode.removeChild(el);
    });
  }
 
 
  function pvzGroupTopbarTabs() {
    var bar = document.getElementById('pvz-mobile-topbar');
    var strip;
    var buttons;
 
    if (!bar) return;
 
    strip = bar.querySelector('.pvz-topbar-tab-strip');
 
    if (!strip) {
      strip = document.createElement('div');
      strip.className = 'pvz-topbar-tab-strip';
      strip.setAttribute('aria-label', '상단 도구');
    }
 
    buttons = [
      bar.querySelector('.pvz-mobile-nav-button[data-pvz-mobile-panel="browse"]'),
      bar.querySelector('.pvz-mobile-nav-button[data-pvz-mobile-panel="settings"]'),
      bar.querySelector('.pvz-mobile-nav-button[data-pvz-mobile-panel="account"]')
    ].filter(Boolean);
 
    if (!buttons.length) return;
 
    if (strip.parentNode !== bar) {
      bar.insertBefore(strip, bar.firstChild);
    }
 
    buttons.forEach(function (button) {
      if (button.parentNode !== strip) {
        strip.appendChild(button);
      }
    });
  }
 
  function pvzEnsureTopbar() {
    var old = document.getElementById('pvz-mobile-topbar');
    var bar;
    var menuButton;
    var searchForm;
    var searchInput;
    var alertsWrap;
    var alertsButton;
    var alertsPopover;
    var alertsHeader;
    var alertsBody;
    var alertsFooter;
    var allAlerts;
    var preferencesLink;
    var accountButton;
    var settingsButton;
 
    if (!document.body) return;
 
    document.documentElement.classList.add('pvz-modern-ui');
 
    pvzCleanupOldBars();
 
    /* 데스크톱은 pvz-desktop-utilitybar만 사용한다. 예전 pvz-mobile-topbar 검색바는 만들지 않는다. */
    if (window.matchMedia && window.matchMedia('(min-width: 721px)').matches) {
      if (old && old.parentNode) old.parentNode.removeChild(old);
      return;
    }
 
    /* 모바일 폭에서만 기존 상단바가 검색만 남거나 버튼이 빠지는 문제를 막기 위해 매번 재생성한다. */
    if (old && old.parentNode) {
      old.parentNode.removeChild(old);
    }
 
    bar = document.createElement('header');
    bar.id = 'pvz-mobile-topbar';
    bar.className = 'pvz-mobile-topbar';
    bar.setAttribute('data-pvz-topbar', 'true');
    bar.setAttribute('aria-label', '식좀위키 상단 바');
    bar.style.setProperty('position', 'absolute', 'important');
    bar.style.setProperty('top', '0', 'important');
    bar.style.setProperty('right', '0', 'important');
    bar.style.setProperty('left', 'auto', 'important');
    bar.style.setProperty('transform', 'none', 'important');
 
    menuButton = document.createElement('button');
    menuButton.type = 'button';
    menuButton.className = 'pvz-mobile-nav-button';
    menuButton.title = '둘러보기';
    menuButton.setAttribute('aria-label', '둘러보기');
    menuButton.setAttribute('data-pvz-mobile-panel', 'browse');
    pvzSetIconOnly(menuButton, 'pvz-icon-menu');
 
    searchForm = document.createElement('form');
    searchForm.className = 'pvz-mobile-search-form';
    searchForm.setAttribute('role', 'search');
 
    searchInput = document.createElement('input');
    searchInput.id = 'pvz-mobile-search-input';
    searchInput.className = 'pvz-mobile-search-input';
    searchInput.type = 'search';
    searchInput.placeholder = '문서 검색';
    searchInput.autocomplete = 'off';
 
    searchInput.addEventListener('input', function () {
      pvzScheduleSearchSuggestions(searchInput.value);
    });
 
    searchInput.addEventListener('focus', function () {
      document.documentElement.classList.add('pvz-mobile-search-focused');
      pvzPositionSearchPanel();
      pvzScheduleSearchSuggestions(searchInput.value);
    });
 
    searchInput.addEventListener('blur', function () {
      window.setTimeout(function () {
        document.documentElement.classList.remove('pvz-mobile-search-focused');
      }, 200);
    });
 
    searchInput.addEventListener('keydown', pvzHandleSearchKeydown);
 
    searchForm.addEventListener('submit', function (event) {
      event.preventDefault();
      if (searchInput.value.replace(/\s+/g, ' ').trim()) {
        window.location.href = pvzGetSearchUrl(searchInput.value);
      }
    });
 
    searchForm.appendChild(searchInput);
 
    alertsWrap = document.createElement('div');
    alertsWrap.id = 'pvz-alerts-wrap';
    alertsWrap.className = 'pvz-alerts-wrap';
 
    alertsButton = document.createElement('button');
    alertsButton.type = 'button';
    alertsButton.id = 'pvz-alerts-button';
    alertsButton.className = 'pvz-mobile-nav-button';
    alertsButton.title = '알림';
    alertsButton.setAttribute('aria-label', '알림');
    pvzSetIconOnly(alertsButton, 'pvz-icon-bell');
 
    alertsPopover = document.createElement('div');
    alertsPopover.id = 'pvz-alerts-popover';
    alertsPopover.className = 'pvz-alerts-popover';
 
    alertsHeader = document.createElement('div');
    alertsHeader.className = 'pvz-alerts-popover-header';
    alertsHeader.appendChild(pvzCreateIcon('pvz-icon-bell'));
 
    var headerText = document.createElement('span');
    headerText.textContent = '알림';
    alertsHeader.appendChild(headerText);
 
    alertsBody = document.createElement('div');
    alertsBody.className = 'pvz-alerts-popover-body';
    alertsBody.textContent = '새 알림이 없습니다.';
 
    alertsFooter = document.createElement('div');
    alertsFooter.className = 'pvz-alerts-popover-footer';
 
    allAlerts = document.createElement('a');
    allAlerts.href = pvzGetUrl('Special:Notifications');
    allAlerts.textContent = '전체 알림';
 
    preferencesLink = document.createElement('a');
    preferencesLink.href = pvzGetUrl('Special:Preferences');
    preferencesLink.textContent = '환경설정';
 
    alertsFooter.appendChild(allAlerts);
    alertsFooter.appendChild(preferencesLink);
 
    alertsPopover.appendChild(alertsHeader);
    alertsPopover.appendChild(alertsBody);
    alertsPopover.appendChild(alertsFooter);
 
    alertsWrap.appendChild(alertsButton);
    alertsWrap.appendChild(alertsPopover);
 
    accountButton = document.createElement('button');
    accountButton.type = 'button';
    accountButton.className = 'pvz-mobile-nav-button';
    accountButton.title = '계정';
    accountButton.setAttribute('aria-label', '계정');
    accountButton.setAttribute('data-pvz-mobile-panel', 'account');
    pvzSetIconOnly(accountButton, 'pvz-icon-account');
 
    settingsButton = document.createElement('button');
    settingsButton.type = 'button';
    settingsButton.className = 'pvz-mobile-nav-button';
    settingsButton.title = '화면 설정';
    settingsButton.setAttribute('aria-label', '화면 설정');
    settingsButton.setAttribute('data-pvz-mobile-panel', 'settings');
    pvzSetIconOnly(settingsButton, 'pvz-icon-settings');
 
    if (window.matchMedia && window.matchMedia('(max-width: 720px)').matches) {
      bar.appendChild(menuButton);
      bar.appendChild(searchForm);
      bar.appendChild(alertsWrap);
      bar.appendChild(settingsButton);
      bar.appendChild(accountButton);
    } else {
      bar.appendChild(searchForm);
      bar.appendChild(alertsWrap);
      bar.appendChild(accountButton);
    }
 
    document.body.insertBefore(bar, document.body.firstChild);
 
    pvzCreateSearchPanel();
    if (!document.getElementById('pvz-mobile-panel-browse')) pvzCreatePanels();
    pvzPositionSearchPanel();
  }
 
  function pvzEnsureDesktopUtilityBar() {
    var old = document.getElementById('pvz-desktop-utilitybar');
    var bar;
    var searchForm;
    var searchInput;
    var alertsWrap;
    var alertsButton;
    var alertsPopover;
    var alertsHeader;
    var alertsBody;
    var alertsFooter;
    var allAlerts;
    var preferencesLink;
    var accountButton;
 
    if (!document.body) return;
 
    /* 모바일에서는 기존 모바일 상단바를 사용한다. */
    if (window.matchMedia && window.matchMedia('(max-width: 720px)').matches) {
      if (old && old.parentNode) old.parentNode.removeChild(old);
      return;
    }
 
    if (old) {
      if (
        old.querySelector('#pvz-desktop-search-input') &&
        old.querySelector('#pvz-desktop-alerts-button') &&
        old.querySelector('#pvz-desktop-account-button')
      ) {
        return;
      }
 
      if (old.parentNode) old.parentNode.removeChild(old);
    }
 
    bar = document.createElement('div');
    bar.id = 'pvz-desktop-utilitybar';
    bar.className = 'pvz-desktop-utilitybar';
    bar.setAttribute('aria-label', '식좀위키 데스크톱 유틸리티 바');
 
    searchForm = document.createElement('form');
    searchForm.className = 'pvz-desktop-search-form';
    searchForm.setAttribute('role', 'search');
 
    searchInput = document.createElement('input');
    searchInput.id = 'pvz-desktop-search-input';
    searchInput.className = 'pvz-desktop-search-input';
    searchInput.type = 'search';
    searchInput.placeholder = '문서 검색';
    searchInput.autocomplete = 'off';
 
    searchInput.addEventListener('input', function () {
      pvzScheduleSearchSuggestions(searchInput.value);
    });
 
    searchInput.addEventListener('focus', function () {
      document.documentElement.classList.add('pvz-mobile-search-focused');
      pvzPositionSearchPanel();
      pvzScheduleSearchSuggestions(searchInput.value);
    });
 
    searchInput.addEventListener('blur', function () {
      window.setTimeout(function () {
        document.documentElement.classList.remove('pvz-mobile-search-focused');
      }, 200);
    });
 
    searchInput.addEventListener('keydown', pvzHandleSearchKeydown);
 
    searchForm.addEventListener('submit', function (event) {
      event.preventDefault();
      if (searchInput.value.replace(/\s+/g, ' ').trim()) {
        window.location.href = pvzGetSearchUrl(searchInput.value);
      }
    });
 
    searchForm.appendChild(searchInput);
 
    alertsWrap = document.createElement('div');
    alertsWrap.id = 'pvz-desktop-alerts-wrap';
    alertsWrap.className = 'pvz-desktop-alerts-wrap';
 
    alertsButton = document.createElement('button');
    alertsButton.type = 'button';
    alertsButton.id = 'pvz-desktop-alerts-button';
    alertsButton.className = 'pvz-desktop-util-button';
    alertsButton.title = '알림';
    alertsButton.setAttribute('aria-label', '알림');
    pvzSetIconOnly(alertsButton, 'pvz-icon-bell');
 
    alertsPopover = document.createElement('div');
    alertsPopover.id = 'pvz-desktop-alerts-popover';
    alertsPopover.className = 'pvz-desktop-alerts-popover';
 
    alertsHeader = document.createElement('div');
    alertsHeader.className = 'pvz-desktop-alerts-popover-header';
    alertsHeader.textContent = '알림';
 
    alertsBody = document.createElement('div');
    alertsBody.className = 'pvz-desktop-alerts-popover-body';
    alertsBody.textContent = '새 알림이 없습니다.';
 
    alertsFooter = document.createElement('div');
    alertsFooter.className = 'pvz-desktop-alerts-popover-footer';
 
    allAlerts = document.createElement('a');
    allAlerts.href = pvzGetUrl('Special:Notifications');
    allAlerts.textContent = '전체 알림';
 
    preferencesLink = document.createElement('a');
    preferencesLink.href = pvzGetUrl('Special:Preferences');
    preferencesLink.textContent = '환경설정';
 
    alertsFooter.appendChild(allAlerts);
    alertsFooter.appendChild(preferencesLink);
 
    alertsPopover.appendChild(alertsHeader);
    alertsPopover.appendChild(alertsBody);
    alertsPopover.appendChild(alertsFooter);
 
    alertsWrap.appendChild(alertsButton);
    alertsWrap.appendChild(alertsPopover);
 
    alertsButton.addEventListener('click', function (event) {
      event.preventDefault();
      event.stopPropagation();
      alertsWrap.classList.toggle('is-open');
    });
 
    accountButton = document.createElement('button');
    accountButton.type = 'button';
    accountButton.id = 'pvz-desktop-account-button';
    accountButton.className = 'pvz-desktop-util-button pvz-mobile-nav-button';
    accountButton.title = '계정';
    accountButton.setAttribute('aria-label', '계정');
    accountButton.setAttribute('data-pvz-mobile-panel', 'account');
    pvzSetIconOnly(accountButton, 'pvz-icon-account');
 
    /* 왼쪽부터 검색바, 알림, 계정. 따라서 오른쪽 끝 기준은 계정 → 알림 → 검색바. */
    bar.appendChild(searchForm);
    bar.appendChild(alertsWrap);
    bar.appendChild(accountButton);
 
    document.body.insertBefore(bar, document.body.firstChild);
 
    pvzCreateSearchPanel();
    if (!document.getElementById('pvz-mobile-panel-account')) pvzCreatePanels();
    pvzPositionSearchPanel();
  }
 
  function pvzEnsureLogo() {
    var old = document.getElementById('pvz-page-logo-link');
    var topbar = document.getElementById('pvz-mobile-topbar');
    var logo;
    var img;
    if (old || !document.body) return;
    logo = document.createElement('a');
    logo.id = 'pvz-page-logo-link';
    logo.className = 'pvz-page-logo-link';
    logo.href = pvzGetUrl('식물 vs 좀비 위키');
    logo.title = '식물 vs 좀비 위키';
    logo.setAttribute('aria-label', '식물 vs 좀비 위키로 이동');
    img = document.createElement('img');
    img.src = '/wiki/Special:Redirect/file/PvZKR_Wiki_Logo2.png';
    img.alt = 'Plants vs. Zombies 위키';
    img.loading = 'eager';
    logo.appendChild(img);
    if (topbar && topbar.parentNode === document.body && topbar.nextSibling) document.body.insertBefore(logo, topbar.nextSibling);
    else if (topbar && topbar.parentNode === document.body) document.body.appendChild(logo);
    else document.body.insertBefore(logo, document.body.firstChild);
  }
 
  function pvzCreateSideLink(label, href) {
    var a = document.createElement('a');
    a.className = 'pvz-board-side-link';
    a.href = href;
    a.textContent = label;
    return a;
  }
 
  function pvzCreateSideSection(title, items) {
    var section = document.createElement('section');
    var h = document.createElement('div');
    var paper = document.createElement('div');
    section.className = 'pvz-board-side-section pvz-side-section-' + String(title || '').replace(/\s+/g, '-');
    h.className = 'pvz-board-side-title';
    h.textContent = title;
    paper.className = 'pvz-board-side-paper';
    items.forEach(function (item) { paper.appendChild(pvzCreateSideLink(item.label, item.href)); });
    section.appendChild(h);
    section.appendChild(paper);
    return section;
  }
 
  function pvzCreateSideNav() {
    var nav = document.createElement('aside');
    var pageName = pvzGetPageName();
    var printableHref = window.location.href.split('#')[0] + (window.location.href.indexOf('?') === -1 ? '?printable=yes' : '&printable=yes');
 
    nav.className = 'pvz-board-side-nav';
    nav.setAttribute('aria-label', '위키 보조창');
 
    nav.appendChild(pvzCreateSideSection('둘러보기', [
      { label: '최근 바뀜', href: pvzGetUrl('Special:RecentChanges') },
      { label: '임의 문서', href: pvzGetUrl('Special:Random') },
      { label: '분류', href: pvzGetUrl('Special:Categories') },
      { label: '미디어위키 도움말', href: pvzGetUrl('Help:Contents') }
    ]));
 
    nav.appendChild(pvzCreateSideSection('문서 도구', [
      { label: '새 문서', href: pvzGetUrl('Special:NewPages') },
      { label: '파일 올리기', href: pvzGetUrl('Special:Upload') },
      { label: '여기로 링크하는 문서', href: pvzGetUrl('Special:WhatLinksHere/' + pageName) },
      { label: '인쇄용 판', href: printableHref },
      { label: '문서 정보', href: pvzGetUrl(pageName) + '?action=info' }
    ]));
 
    nav.appendChild(pvzCreateSideSection('위키 관리', [
      { label: '특수 문서', href: pvzGetUrl('Special:SpecialPages') },
      { label: '핵심 설정 관리', href: pvzGetUrl('Special:ManageWiki/settings') },
      { label: '확장 기능 관리', href: pvzGetUrl('Special:ManageWiki/extensions') },
      { label: '이름공간 관리', href: pvzGetUrl('Special:ManageWiki/namespaces') },
      { label: '백업 관리', href: pvzGetUrl('Special:DataDump') }
    ]));
 
    return nav;
  }
 
  function pvzCreateRelatedPanel() {
    var panel = document.createElement('aside');
    var title = document.createElement('div');
    var list = document.createElement('div');
    panel.id = 'pvz-board-related-panel';
    panel.className = 'pvz-board-related-panel';
    panel.setAttribute('aria-label', '관련 문서');
    title.className = 'pvz-board-related-title';
    title.textContent = '관련 문서';
    list.id = 'pvz-board-related-list';
    list.className = 'pvz-board-related-list';
    panel.appendChild(title);
    panel.appendChild(list);
    return panel;
  }
 
  function pvzCreateRelatedCard(titleText, href, thumb) {
    var link = document.createElement('a');
    var media = document.createElement('div');
    var titleBar = document.createElement('div');
    var title = document.createElement('span');
    link.className = 'pvz-related-card';
    link.href = href;
    media.className = 'pvz-related-card-media';
    if (thumb) {
      var img = document.createElement('img');
      img.src = thumb;
      img.alt = '';
      img.loading = 'lazy';
      media.appendChild(img);
    }
    titleBar.className = 'pvz-related-card-titlebar';
    title.className = 'pvz-related-card-title';
    title.textContent = titleText || '문서 이름';
    titleBar.appendChild(title);
    link.appendChild(media);
    link.appendChild(titleBar);
    return link;
  }
 
  function pvzCollectRelatedTitles(limit) {
    var current = pvzGetPageName().replace(/_/g, ' ');
    var contentText = document.getElementById('mw-content-text');
    var links = contentText ? contentText.querySelectorAll('a[href]') : [];
    var seen = {};
    var results = [];
    pvzArray(links).forEach(function (link) {
      var href = link.getAttribute('href') || '';
      var title = '';
      if (!href || results.length >= limit) return;
      if (href.indexOf('#') === 0) return;
      if (href.indexOf('/wiki/') === 0) {
        title = decodeURIComponent(href.replace(/^\/wiki\//, '').split('#')[0].split('?')[0]).replace(/_/g, ' ');
      } else if (link.dataset && link.dataset.title) {
        title = String(link.dataset.title).replace(/_/g, ' ');
      }
      if (!title || title === current) return;
      if (/^(Special|File|파일|Category|분류|Template|틀|Help|User|사용자|Talk|토론):/i.test(title)) return;
      if (seen[title]) return;
      seen[title] = true;
      results.push(title);
    });
    return results.slice(0, limit);
  }
 
  function pvzRenderRelatedCards(items) {
    var list = document.getElementById('pvz-board-related-list');
    if (!list) return;
    list.innerHTML = '';
    if (!items || !items.length) items = [{ title: '대문', href: pvzGetUrl('대문'), thumb: '' }];
    items.forEach(function (item) { list.appendChild(pvzCreateRelatedCard(item.title, item.href, item.thumb)); });
  }
 
  function pvzLoadRelatedDocs() {
    var titles = pvzCollectRelatedTitles(12);
    var url;
    pvzRenderRelatedCards(titles.map(function (title) { return { title: title, href: pvzGetUrl(title), thumb: '' }; }));
    if (!titles.length || !window.fetch) return;
    url = pvzGetApiUrl() + '?action=query&format=json&formatversion=2&prop=pageimages&piprop=thumbnail&pithumbsize=260&titles=' + encodeURIComponent(titles.join('|'));
    fetch(url, { credentials: 'same-origin' })
      .then(function (res) { return res.json(); })
      .then(function (data) {
        var pages = data && data.query && Array.isArray(data.query.pages) ? data.query.pages : [];
        var map = {};
        pages.forEach(function (page) { if (page && page.title) map[page.title] = page.thumbnail && page.thumbnail.source ? page.thumbnail.source : ''; });
        pvzRenderRelatedCards(titles.map(function (title) { return { title: title, href: pvzGetUrl(title), thumb: map[title] || '' }; }));
      })
      .catch(function () {});
  }
 
  function pvzSetRelatedOpen(open) {
    document.documentElement.classList.toggle('pvz-related-open', !!open);
    if (document.body) document.body.classList.toggle('pvz-related-open', !!open);
    var button = document.getElementById('pvz-side-toggle');
    if (button) {
      button.setAttribute('aria-expanded', open ? 'true' : 'false');
      button.setAttribute('aria-label', open ? '관련 문서 닫기' : '관련 문서 열기');
      button.setAttribute('title', open ? '관련 문서 닫기' : '관련 문서 열기');
      button.innerHTML = '';
      button.appendChild(pvzCreateIcon(open ? 'pvz-icon-chevron-left' : 'pvz-icon-chevron-right'));
    }
  }
 
  function pvzEnsureSideToggle() {
    var button = document.getElementById('pvz-side-toggle');
    if (button || !document.body) return;
    button = document.createElement('button');
    button.type = 'button';
    button.id = 'pvz-side-toggle';
    button.setAttribute('aria-expanded', 'false');
    button.setAttribute('aria-label', '관련 문서 열기');
    button.setAttribute('title', '관련 문서 열기');
    button.appendChild(pvzCreateIcon('pvz-icon-chevron-right'));
    document.body.appendChild(button);
  }
 
  function pvzSetAlertsOpen(open) {
    var wrap = document.getElementById('pvz-alerts-wrap');
    if (wrap) wrap.classList.toggle('is-open', !!open);
  }
 
  function pvzToggleAlertsOpen() {
    var wrap = document.getElementById('pvz-alerts-wrap');
    if (!wrap) return;
    pvzSetAlertsOpen(!wrap.classList.contains('is-open'));
  }
 
  function pvzHeadingText(heading) {
    var clone;
 
    if (!heading) return '';
 
    clone = heading.cloneNode(true);
    clone.querySelectorAll('.mw-editsection, .mw-headline-number, .toctogglecheckbox').forEach(function (el) {
      el.remove();
    });
 
    return pvzText(clone);
  }
 
  function pvzSafeAnchor(text, index) {
    var id = String(text || '')
      .trim()
      .replace(/\s+/g, '-')
      .replace(/[^\w가-힣ぁ-んァ-ン一-龥-]/g, '');
 
    if (!id) id = 'section-' + index;
 
    return 'pvz-section-' + id + '-' + index;
  }
 
  function pvzHeadingId(heading, text, index) {
    var headline = heading.querySelector ? heading.querySelector('.mw-headline') : null;
    var id;
 
    if (headline && headline.id) return headline.id;
    if (heading.id) return heading.id;
 
    id = pvzSafeAnchor(text, index);
    heading.id = id;
    return id;
  }
 
  function pvzSkipHeading(heading) {
    var text = pvzHeadingText(heading);
 
    if (!text) return true;
 
    if (
      heading.closest('.pvz-custom-toc-wrap') ||
      heading.closest('.toc') ||
      heading.closest('#toc') ||
      heading.closest('table') ||
      heading.closest('.infobox') ||
      heading.closest('.navbox') ||
      heading.closest('.metadata') ||
      heading.closest('.catlinks') ||
      heading.closest('.mw-references-wrap') ||
      heading.closest('.reference')
    ) {
      return true;
    }
 
    return text === '목차' || text === 'Contents' || text === '각주' ||
      text === 'References' || text === '분류';
  }
 
  function pvzIsTextParagraph(el) {
    if (!el || el.tagName !== 'P') return false;
    return (el.textContent || '').replace(/\s+/g, ' ').trim().length > 0;
  }
 
  function pvzCreateCustomToc() {
    var contentText = document.getElementById('mw-content-text');
    var contentRoot = contentText && (
      contentText.querySelector('.mw-parser-output') || contentText
    );
    var existingWrap;
    var nativeTocs;
    var headings;
    var leadParagraph;
    var wrap;
    var toc;
    var head;
    var title;
    var toggle;
    var list;
    var counters = [0, 0, 0, 0, 0];
 
    function getDepth(heading) {
      var level = parseInt(heading.tagName.replace('H', ''), 10);
      var depth = level - 1;
 
      if (depth < 1) depth = 1;
      if (depth > 5) depth = 5;
 
      return depth;
    }
 
    function getNumber(depth) {
      var i;
      var parts = [];
 
      counters[depth - 1] += 1;
 
      for (i = depth; i < counters.length; i += 1) {
        counters[i] = 0;
      }
 
      for (i = 0; i < depth; i += 1) {
        if (!counters[i]) counters[i] = 1;
        parts.push(counters[i]);
      }
 
      return parts.join('.');
    }
 
    function isExcludedLeadContainer(element) {
      if (!element || !element.matches) return false;
 
      return element.matches(
        'table, figure, .thumb, .tright, .tleft, .floatright, .floatleft, .floatnone, ' +
        '.infobox, .pvz-cp-infobox, .pvz-character-infobox, .character-infobox, ' +
        '.navbox, .metadata, .catlinks, .mw-references-wrap, ' +
        '.pvz-message, .pvz-custom-toc-wrap, #toc, .toc'
      );
    }
 
    function isLeadParagraph(element) {
      var clone;
      var text;
 
      /*
        첫 문단은 .mw-parser-output의 직접 자식인 <p>만 인정한다.
        틀이나 정보상자 내부의 <p>를 첫 문장으로 오인하지 않는다.
      */
      if (!element || element.parentNode !== contentRoot || element.tagName !== 'P') {
        return false;
      }
 
      if (isExcludedLeadContainer(element)) return false;
 
      /*
        TemplateStyles/ResourceLoader가 넣은 style 요소나
        CSS 전용 문단은 실제 본문 문단으로 취급하지 않는다.
      */
      if (
        element.querySelector(
          'style, script, template, noscript, ' +
          'link[rel="mw-deduplicated-inline-style"], ' +
          '[data-mw-deduplicate]'
        )
      ) {
        return false;
      }
 
      clone = element.cloneNode(true);
 
      clone.querySelectorAll(
        'figure, .thumb, .mw-file-description, .mw-default-size, ' +
        '.mw-image-border, .reference, sup, .mw-editsection, ' +
        'style, script, template, noscript, link, [data-mw-deduplicate]'
      ).forEach(function (node) {
        node.remove();
      });
 
      text = (clone.textContent || '').replace(/\s+/g, ' ').trim();
 
      /*
        일부 파서 구조에서는 CSS가 순수 텍스트 노드로 남을 수 있으므로
        대표적인 CSS 시작 패턴도 추가로 제외한다.
      */
      if (
        /^(?:\.mw-parser-output\b|@media\b|@supports\b|@layer\b|:root\b)/.test(text) &&
        /[{};]/.test(text)
      ) {
        return false;
      }
 
      return text.length > 0;
    }
 
    function findLeadParagraph() {
      var children;
      var i;
      var child;
 
      if (!contentRoot) return null;
 
      children = pvzArray(contentRoot.children);
 
      for (i = 0; i < children.length; i += 1) {
        child = children[i];
 
        if (isExcludedLeadContainer(child)) continue;
 
        if (isLeadParagraph(child)) {
          return child;
        }
      }
 
      return null;
    }
 
    function placeTocAfterLead(tocWrap, paragraph) {
      if (
        !tocWrap ||
        !paragraph ||
        paragraph.parentNode !== contentRoot
      ) {
        return false;
      }
 
      if (
        tocWrap.parentNode === contentRoot &&
        paragraph.nextSibling === tocWrap
      ) {
        return true;
      }
 
      contentRoot.insertBefore(tocWrap, paragraph.nextSibling);
 
      return true;
    }
 
    if (!contentRoot || contentRoot.querySelector('.pvz-no-custom-toc')) return;
 
    leadParagraph = findLeadParagraph();
 
    /*
      실제 첫 본문 문단이 확인되기 전에는 목차를 임의 위치에 생성하지 않는다.
      틀:작성중이나 캐릭터 정보상자 내부 문단은 첫 문단 후보에서 제외한다.
    */
    if (!leadParagraph) return;
 
    existingWrap = contentRoot.querySelector('.pvz-custom-toc-wrap');
 
    if (existingWrap) {
      placeTocAfterLead(existingWrap, leadParagraph);
      return;
    }
 
    headings = pvzArray(
      contentRoot.querySelectorAll('h2, h3, h4, h5, h6')
    ).filter(function (heading) {
      return !pvzSkipHeading(heading);
    });
 
    if (headings.length < 2) return;
 
    nativeTocs = pvzArray(
      contentRoot.querySelectorAll('#toc, .toc')
    ).filter(function (node) {
      return node && !(
        node.classList &&
        node.classList.contains('pvz-custom-toc')
      );
    });
 
    nativeTocs.forEach(function (old) {
      if (old && old.parentNode) {
        old.parentNode.removeChild(old);
      }
    });
 
    wrap = document.createElement('div');
    wrap.className = 'pvz-custom-toc-wrap';
 
    toc = document.createElement('nav');
    toc.className = 'pvz-custom-toc';
    toc.setAttribute('aria-label', '목차');
 
    head = document.createElement('div');
    head.className = 'pvz-custom-toc-head';
 
    title = document.createElement('div');
    title.className = 'pvz-custom-toc-title';
    title.textContent = '목차';
 
    toggle = document.createElement('button');
    toggle.type = 'button';
    toggle.className = 'pvz-custom-toc-toggle';
    toggle.setAttribute('aria-expanded', 'true');
    toggle.textContent = '접기';
 
    toggle.addEventListener('click', function (event) {
      var collapsed;


      event.preventDefault();
var ACTION_OFFSET = 230;
var SEARCH_WIDTH = 205;
var SEARCH_DOWN_OFFSET = 5;
var CONTENT_TOP = 24;


      collapsed = !toc.classList.contains('is-collapsed');
function getCactionsParts() {
      toc.classList.toggle('is-collapsed', collapsed);
var menu = document.getElementById('p-cactions');
      toggle.setAttribute(
        'aria-expanded',
        collapsed ? 'false' : 'true'
      );
      toggle.textContent = collapsed ? '펼치기' : '접기';
    });


    head.appendChild(title);
if (!menu) {
    head.appendChild(toggle);
return null;
}


    list = document.createElement('ol');
return {
    list.className = 'pvz-custom-toc-list';
menu: menu,
label:
document.getElementById('p-cactions-label') ||
menu.querySelector('.vector-menu-heading'),
checkbox: menu.querySelector(
'input.vector-menu-checkbox, input[type="checkbox"]'
),
content: menu.querySelector('.vector-menu-content')
};
}


    headings.forEach(function (heading, index) {
function isCactionsOpen(parts) {
      var depth = getDepth(heading);
if (!parts) {
      var level = depth + 1;
return false;
      var text = pvzHeadingText(heading);
}
      var anchor = pvzHeadingId(heading, text, index + 1);
      var number = getNumber(depth);
      var item = document.createElement('li');
      var link = document.createElement('a');
      var numberSpan = document.createElement('span');
      var textSpan = document.createElement('span');


      item.className =
if (parts.checkbox && parts.checkbox.checked) {
        'pvz-custom-toc-item pvz-custom-toc-level-' +
return true;
        level +
}
        ' pvz-custom-toc-depth-' +
        depth;


      link.href = '#' + anchor;
if (
parts.menu.classList.contains('vector-menu-dropdown-active') ||
parts.menu.classList.contains('pvz-cactions-open')
) {
return true;
}


      numberSpan.className = 'pvz-custom-toc-number';
if (parts.label) {
      numberSpan.textContent = number;
return parts.label.getAttribute('aria-expanded') === 'true';
}


      textSpan.className = 'pvz-custom-toc-text';
return false;
      textSpan.textContent = text;
}


      link.appendChild(numberSpan);
function closeCactions(parts) {
      link.appendChild(textSpan);
if (!parts) {
      item.appendChild(link);
return;
      list.appendChild(item);
}
    });


    toc.appendChild(head);
if (parts.checkbox) {
    toc.appendChild(list);
parts.checkbox.checked = false;
    wrap.appendChild(toc);
parts.checkbox.dispatchEvent(
new Event('change', { bubbles: true })
);
}


    placeTocAfterLead(wrap, leadParagraph);
parts.menu.classList.remove(
  }
'pvz-cactions-open',
'vector-menu-dropdown-active'
);


  function pvzEnsureRelatedPanel() {
if (parts.label) {
    var panel = document.getElementById('pvz-board-related-panel') ||
parts.label.setAttribute('aria-expanded', 'false');
      document.querySelector('.pvz-board-related-panel');
}


    if (!document.body) return panel;
if (parts.content) {
parts.content.setAttribute('aria-hidden', 'true');
}
}


    if (!panel) {
function handleCactionsClick(event) {
      panel = pvzCreateRelatedPanel();
var parts = getCactionsParts();
    }
var label;


    /* 관련 문서 창은 왼쪽 레일 안에 두지 않고 body 직속으로 둔다.
if (!parts) {
      이렇게 해야 blur 막이나 본문창보다 항상 위에 올라올 수 있다. */
return;
    if (panel.parentNode !== document.body) {
}
      document.body.appendChild(panel);
    }


    return panel;
label = event.target.closest(
  }
'#p-cactions-label, #p-cactions > .vector-menu-heading'
);


  function pvzBuildBoard() {
if (label && isCactionsOpen(parts)) {
    var contentText = document.getElementById('mw-content-text');
event.preventDefault();
    var boardRoot;
event.stopImmediatePropagation();
    var frameOuter;
closeCactions(parts);
    var frameThird;
return;
    var frameSecond;
}
    var frameInner;
    var boardBody;
    var paper;
    var paperMain;
    var paperMeta;
    var sideNav;
    var relatedPanel;
    var leftRail;
    var logo;
    var catlinks;
    var firstChild;
    if (!contentText || !document.body) return;
    pvzEnsureSideToggle();
    if (document.body.classList.contains('pvz-board-ready')) {
      logo = document.getElementById('pvz-page-logo-link');
      boardRoot = document.getElementById('bodyContent') || document.querySelector('#content') || contentText.parentElement;
      if (boardRoot && boardRoot.classList.contains('pvz-board-root')) {
        leftRail = boardRoot.querySelector('.pvz-board-left-rail');
        sideNav = boardRoot.querySelector('.pvz-board-side-nav');
        relatedPanel = pvzEnsureRelatedPanel();
        if (!leftRail) { leftRail = document.createElement('div'); leftRail.className = 'pvz-board-left-rail'; boardRoot.insertBefore(leftRail, boardRoot.firstChild); }
        if (logo && logo.parentNode !== leftRail) leftRail.appendChild(logo);
        if (!sideNav) leftRail.appendChild(pvzCreateSideNav());
        relatedPanel = pvzEnsureRelatedPanel();
      }
      pvzLoadRelatedDocs();
      pvzCreateCustomToc();
      return;
    }
    boardRoot = document.getElementById('bodyContent') || document.querySelector('#content') || contentText.parentElement;
    if (!boardRoot) return;
    boardRoot.classList.add('pvz-board-root');
    logo = document.getElementById('pvz-page-logo-link');
    if (logo && logo.parentNode !== boardRoot) boardRoot.insertBefore(logo, boardRoot.firstChild);
    frameOuter = document.createElement('div'); frameOuter.className = 'pvz-board-frame-outer-real';
    frameThird = document.createElement('div'); frameThird.className = 'pvz-board-frame-third-real';
    frameSecond = document.createElement('div'); frameSecond.className = 'pvz-board-frame-second-real';
    frameInner = document.createElement('div'); frameInner.className = 'pvz-board-frame-inner-real';
    boardBody = document.createElement('div'); boardBody.className = 'pvz-board-body';
    paper = document.createElement('div'); paper.className = 'pvz-board-paper';
    paperMain = document.createElement('div'); paperMain.className = 'pvz-board-paper-main';
    paperMeta = document.createElement('div'); paperMeta.className = 'pvz-board-paper-meta';
    sideNav = pvzCreateSideNav(); relatedPanel = pvzEnsureRelatedPanel();
    leftRail = document.createElement('div'); leftRail.className = 'pvz-board-left-rail';
    if (logo) leftRail.appendChild(logo);
    leftRail.appendChild(sideNav);
    firstChild = boardRoot.firstChild;
    boardRoot.insertBefore(leftRail, firstChild || null);
    boardRoot.insertBefore(frameOuter, leftRail.nextSibling || null);
    paperMain.appendChild(contentText);
    catlinks = document.getElementById('catlinks') || document.querySelector('.catlinks');
    if (catlinks && !paperMeta.contains(catlinks)) paperMeta.appendChild(catlinks);
    paper.appendChild(paperMain); paper.appendChild(paperMeta);
    boardBody.appendChild(pvzCreateBoardHead()); boardBody.appendChild(paper);
    frameInner.appendChild(boardBody); frameSecond.appendChild(frameInner); frameThird.appendChild(frameSecond); frameOuter.appendChild(frameThird);
    document.body.classList.add('pvz-board-ready');
      document.documentElement.classList.add('pvz-desktop-booted');
    pvzLoadRelatedDocs();
    pvzCreateCustomToc();
  }


  function pvzMarkBoardActionActive(target) {
if (
    var button = pvzClosest(target, '.pvz-board-btn, .pvz-board-more > summary');
isCactionsOpen(parts) &&
    if (!button) return;
!event.target.closest('#p-cactions')
    document.querySelectorAll('.pvz-board-btn.is-clicked, .pvz-board-more > summary.is-clicked').forEach(function (el) {
) {
      el.classList.remove('is-clicked');
closeCactions(parts);
    });
}
    button.classList.add('is-clicked');
}
  }


  function pvzBindEvents() {
function syncV35Layout() {
    if (window.PVZ_VECTOR_EVENTS_BOUND) return;
var content = document.querySelector('#content');
    window.PVZ_VECTOR_EVENTS_BOUND = true;
var leftNavigation = document.getElementById('left-navigation');
var rightNavigation = document.getElementById('right-navigation');
var search = document.getElementById('pvz-content-search');
var rightGap;
var navigationTop;


    document.addEventListener('click', function (event) {
if (!content || !leftNavigation) {
      var panelButton = pvzClosest(event.target, '.pvz-mobile-nav-button[data-pvz-mobile-panel], .pvz-desktop-util-button[data-pvz-mobile-panel]');
return;
      var panel = pvzClosest(event.target, '.pvz-mobile-sheet');
}
      var panelBackdrop = pvzClosest(event.target, '#pvz-mobile-panel-backdrop');
      var suggestionsPanel = pvzClosest(event.target, '#pvz-search-suggestions');
      var searchInput = pvzClosest(event.target, '#pvz-mobile-search-input');
      var alertsButton = pvzClosest(event.target, '#pvz-alerts-button');
      var alertsWrap = pvzClosest(event.target, '#pvz-alerts-wrap');
      var desktopAlertsWrap = pvzClosest(event.target, '#pvz-desktop-alerts-wrap');
      var sideToggle = pvzClosest(event.target, '#pvz-side-toggle');
      var boardAction = pvzClosest(event.target, '.pvz-board-btn, .pvz-board-more > summary');
      var name;


      if (sideToggle) {
rightGap = Math.max(
        event.preventDefault();
0,
        event.stopPropagation();
window.innerWidth - content.getBoundingClientRect().right
        pvzSetRelatedOpen(!document.body.classList.contains('pvz-related-open'));
);
        return;
      }


      if (boardAction) {
navigationTop =
        pvzMarkBoardActionActive(boardAction);
leftNavigation.getBoundingClientRect().top +
      }
window.scrollY;


      if (alertsButton) {
if (!Number.isFinite(navigationTop)) {
        event.preventDefault();
navigationTop = CONTENT_TOP;
        event.stopPropagation();
}
        pvzToggleAlertsOpen();
        return;
      }


      if (panelButton) {
document.documentElement.style.setProperty(
        event.preventDefault();
'--pvz-content-right-gap',
        event.stopPropagation();
rightGap + 'px'
        name = panelButton.getAttribute('data-pvz-mobile-panel');
);
        pvzTogglePanel(name);
        return;
      }


      if (panelBackdrop) {
document.documentElement.style.setProperty(
        event.preventDefault();
'--pvz-navigation-top',
        pvzClosePanels();
navigationTop + 'px'
        return;
);
      }


      if (!suggestionsPanel && !searchInput) pvzCloseSuggestions();
if (rightNavigation) {
      if (!alertsWrap) pvzSetAlertsOpen(false);
rightNavigation.style.setProperty(
      if (!desktopAlertsWrap) {
'position',
        var desktopAlerts = document.getElementById('pvz-desktop-alerts-wrap');
'absolute',
        if (desktopAlerts) desktopAlerts.classList.remove('is-open');
'important'
      }
);
      if (document.body.classList.contains('pvz-related-open') && !pvzClosest(event.target, '.pvz-board-related-panel') && !sideToggle) {
rightNavigation.style.setProperty(
        pvzSetRelatedOpen(false);
'top',
      }
navigationTop + 'px',
      if (!panel && !panelButton && !panelBackdrop) pvzClosePanels();
'important'
    }, true);
);
rightNavigation.style.setProperty(
'right',
(rightGap + ACTION_OFFSET) + 'px',
'important'
);
rightNavigation.style.setProperty(
'left',
'auto',
'important'
);
rightNavigation.style.setProperty(
'display',
'flex',
'important'
);
rightNavigation.style.setProperty(
'align-items',
'flex-end',
'important'
);
rightNavigation.style.setProperty(
'justify-content',
'flex-end',
'important'
);
rightNavigation.style.setProperty(
'width',
'max-content',
'important'
);
rightNavigation.style.setProperty(
'margin',
'0',
'important'
);
rightNavigation.style.setProperty(
'transform',
'none',
'important'
);
}


    document.addEventListener('keydown', function (event) {
if (search) {
      if (event.key === 'Escape') {
search.style.setProperty(
        pvzCloseSuggestions();
'position',
        pvzClosePanels();
'absolute',
        pvzSetAlertsOpen(false);
'important'
        var desktopAlerts = document.getElementById('pvz-desktop-alerts-wrap');
);
        if (desktopAlerts) desktopAlerts.classList.remove('is-open');
search.style.setProperty(
        pvzSetRelatedOpen(false);
'top',
      }
(navigationTop + SEARCH_DOWN_OFFSET) + 'px',
    });
'important'
);
search.style.setProperty(
'right',
rightGap + 'px',
'important'
);
search.style.setProperty(
'left',
'auto',
'important'
);
search.style.setProperty(
'width',
SEARCH_WIDTH + 'px',
'important'
);
search.style.setProperty(
'max-width',
SEARCH_WIDTH + 'px',
'important'
);
}
}


    window.addEventListener('resize', function () {
function initV35Layout() {
      pvzSyncClasses();
var observer;
      pvzPositionSearchPanel();
      pvzEnsureTopbar();
    pvzEnsureDesktopUtilityBar();
      pvzLoadRelatedDocs();
    });


    window.addEventListener('scroll', function () {
syncV35Layout();
      pvzPositionSearchPanel();
    }, true);
  }


  function pvzInit() {
document.addEventListener(
    pvzSyncClasses();
'click',
    pvzApplyPreferences();
handleCactionsClick,
    pvzEnsureTopbar();
true
    pvzEnsureDesktopUtilityBar();
);
    pvzEnsureLogo();
    pvzBuildBoard();
    pvzBindEvents();


    window.setTimeout(function () {
window.addEventListener(
      pvzSyncClasses();
'resize',
      pvzEnsureTopbar();
syncV35Layout,
    pvzEnsureDesktopUtilityBar();
{ passive: true }
      pvzEnsureLogo();
);
      pvzCreateCustomToc();
    }, 120);


    window.setTimeout(function () {
window.addEventListener(
      pvzSyncClasses();
'orientationchange',
      pvzEnsureTopbar();
syncV35Layout,
    pvzEnsureDesktopUtilityBar();
{ passive: true }
      pvzEnsureLogo();
);
      pvzCreateCustomToc();
    }, 600);


    window.setTimeout(function () {
observer = new MutationObserver(function () {
      pvzSyncClasses();
window.requestAnimationFrame(syncV35Layout);
      pvzEnsureTopbar();
});
    pvzEnsureDesktopUtilityBar();
      pvzEnsureLogo();
      pvzCreateCustomToc();
    }, 1400);
  }


  if (window.mw && mw.hook) {
observer.observe(document.body, {
    mw.hook('wikipage.content').add(function () {
childList: true,
      pvzInit();
subtree: true
    });
});
  }
}


  pvzReady(pvzInit);
if (document.readyState === 'loading') {
document.addEventListener(
'DOMContentLoaded',
initV35Layout,
{ once: true }
);
} else {
initV35Layout();
}
}());
}());

2026년 7월 30일 (목) 13:59 기준 최신판

(function () {
	'use strict';

	var SPIN_CLASS = 'pvz-watch-spinning';
	var WATCHED_CLASS = 'pvz-watch-watched';
	var NOT_WATCHED_CLASS = 'pvz-watch-not-watched';
	var SPIN_TIME = 360;
	var cleanupTimer = 0;

	function getContainer() {
		return document.querySelector(
			'#ca-watch, #ca-unwatch, li.mw-watchlink, a.mw-watchlink'
		);
	}

	function getLink(container) {
		if (!container) {
			return null;
		}

		return container.matches('a') ? container : container.querySelector('a');
	}

	function applyState(isWatched) {
		var container = getContainer();

		if (!container) {
			return;
		}

		container.classList.toggle(WATCHED_CLASS, !!isWatched);
		container.classList.toggle(NOT_WATCHED_CLASS, !isWatched);
	}

	function syncFromMarkup() {
		var container = getContainer();
		var link = getLink(container);
		var href;

		if (!container || !link) {
			return;
		}

		href = link.getAttribute('href') || '';

		applyState(
			container.id === 'ca-unwatch' ||
			href.indexOf('action=unwatch') !== -1
		);
	}

	function spin() {
		var container = getContainer();

		if (!container) {
			return;
		}

		window.clearTimeout(cleanupTimer);
		container.classList.remove(SPIN_CLASS);
		void container.offsetWidth;
		container.classList.add(SPIN_CLASS);

		cleanupTimer = window.setTimeout(function () {
			container.classList.remove(SPIN_CLASS);
		}, SPIN_TIME + 40);
	}

	function handleClick(event) {
		var link = event.target.closest(
			'#ca-watch > a, #ca-unwatch > a, li.mw-watchlink > a, a.mw-watchlink'
		);

		if (link) {
			spin();
		}
	}

	function shortenHistoryLabel() {
		var historyLink = document.querySelector('#ca-history > a');

		if (!historyLink) {
			return;
		}

		Array.prototype.forEach.call(historyLink.childNodes, function (node) {
			if (node.nodeType === Node.TEXT_NODE) {
				node.nodeValue = node.nodeValue.replace(/역사 보기/g, '역사');
			}
		});

		if (historyLink.textContent.trim() === '역사 보기') {
			historyLink.textContent = '역사';
		}

		historyLink.setAttribute('title', '역사');
	}

	function init() {
		var observer;

		shortenHistoryLabel();
		syncFromMarkup();
		document.addEventListener('click', handleClick, true);

		observer = new MutationObserver(function () {
			shortenHistoryLabel();
			syncFromMarkup();
		});

		observer.observe(document.body, {
			subtree: true,
			childList: true,
			attributes: true,
			attributeFilter: ['id', 'href']
		});

		if (window.mw && mw.hook) {
			mw.hook('wikipage.watchlistChange').add(function (isWatched) {
				applyState(isWatched);
				spin();
			});
		}
	}

	if (document.readyState === 'loading') {
		document.addEventListener('DOMContentLoaded', init, { once: true });
	} else {
		init();
	}
}());


(function () {
	'use strict';

	function installSearchButtonIcon(wrapper) {
		var simpleSearch;
		var searchButton;
		var icon;

		if (!wrapper) {
			return;
		}

		simpleSearch = wrapper.querySelector('#simpleSearch');

		if (!simpleSearch) {
			return;
		}

		searchButton =
			simpleSearch.querySelector('#searchButton') ||
			simpleSearch.querySelector('.searchButton:not(#mw-searchButton)');

		if (!searchButton) {
			return;
		}

		searchButton.classList.add('pvz-primary-search-button');

		icon = simpleSearch.querySelector('.pvz-search-button-icon');

		if (!icon) {
			icon = document.createElement('span');
			icon.className = 'pvz-search-button-icon';
			icon.setAttribute('aria-hidden', 'true');
			simpleSearch.appendChild(icon);
		}
	}

	function installTopSearch() {
		var content = document.querySelector('.skin-vector-legacy #content');
		var form = document.querySelector('#searchform');
		var wrapper;

		if (!content || !form || !document.body) {
			return;
		}

		wrapper = document.getElementById('pvz-content-search');

		if (!wrapper) {
			wrapper = document.createElement('div');
			wrapper.id = 'pvz-content-search';
			wrapper.setAttribute('role', 'search');
			wrapper.setAttribute('aria-label', '사이트 검색');
		}

		if (wrapper.parentNode !== document.body) {
			document.body.insertBefore(wrapper, content);
		}

		if (form.parentNode !== wrapper) {
			wrapper.appendChild(form);
		}

		installSearchButtonIcon(wrapper);
		document.documentElement.classList.add('pvz-content-search-ready');
	}

	function initTopSearch() {
		var observer;

		installTopSearch();

		observer = new MutationObserver(function () {
			installTopSearch();
		});

		observer.observe(document.body, {
			childList: true,
			subtree: true
		});
	}

	if (document.readyState === 'loading') {
		document.addEventListener('DOMContentLoaded', initTopSearch, { once: true });
	} else {
		initTopSearch();
	}
}());


(function () {
	'use strict';

	function syncSearchLeft() {
		var content = document.querySelector('.skin-vector-legacy #content');
		var left;

		if (!content) {
			return;
		}

		left = content.getBoundingClientRect().left + window.scrollX;
		document.documentElement.style.setProperty('--pvz-content-left', left + 'px');
	}

	function initSearchAlignment() {
		syncSearchLeft();
		window.addEventListener('resize', syncSearchLeft, { passive: true });
		window.addEventListener('orientationchange', syncSearchLeft, { passive: true });
	}

	if (document.readyState === 'loading') {
		document.addEventListener('DOMContentLoaded', initSearchAlignment, { once: true });
	} else {
		initSearchAlignment();
	}
}());


(function () {
	'use strict';

	function removeObsoleteInterface() {
		var ids = [
			'pvz-related-toggle',
			'pvz-related-menu',
			'pvz-right-panel',
			'pvz-left-panel-toggle',
			'pvz-right-panel-toggle'
		];

		ids.forEach(function (id) {
			var element = document.getElementById(id);

			if (element) {
				element.remove();
			}
		});
	}

	function restoreLogoToPanel(panel) {
		var wrapper = document.getElementById('pvz-sidebar-logo');
		var logo =
			(wrapper && wrapper.querySelector('#p-logo')) ||
			document.querySelector('#p-logo');

		if (!panel || !logo) {
			return;
		}

		if (logo.parentNode !== panel) {
			panel.insertBefore(logo, panel.firstChild);
		}

		if (wrapper) {
			wrapper.remove();
		}
	}

	function syncPanelTop() {
		var content = document.querySelector('.skin-vector-legacy #content');
		var top;

		if (!content) {
			return;
		}

		top = content.getBoundingClientRect().top + window.scrollY;
		document.documentElement.style.setProperty('--pvz-content-top', top + 'px');
	}

	function syncSearchLeft() {
		var content = document.querySelector('.skin-vector-legacy #content');
		var left;

		if (!content) {
			return;
		}

		left = content.getBoundingClientRect().left + window.scrollX;
		document.documentElement.style.setProperty('--pvz-content-left', left + 'px');
	}

	function installV27Interface() {
		var panel = document.querySelector('.skin-vector-legacy #mw-panel');

		removeObsoleteInterface();
		restoreLogoToPanel(panel);
		syncPanelTop();
		syncSearchLeft();
	}

	function initV27Interface() {
		installV27Interface();

		window.addEventListener('resize', function () {
			syncPanelTop();
			syncSearchLeft();
		}, { passive: true });

		window.addEventListener('orientationchange', function () {
			syncPanelTop();
			syncSearchLeft();
		}, { passive: true });
	}

	if (document.readyState === 'loading') {
		document.addEventListener('DOMContentLoaded', initV27Interface, { once: true });
	} else {
		initV27Interface();
	}
}());


(function () {
	'use strict';

	function installGrassDividers(root) {
		var scope = root || document;
		var wrappers;
		var legacyHeadings;

		wrappers = scope.querySelectorAll(
			'.skin-vector-legacy .mw-parser-output .mw-heading2'
		);

		Array.prototype.forEach.call(wrappers, function (wrapper) {
			var divider;

			wrapper.classList.add('pvz-grass-heading');

			divider = wrapper.querySelector(
				':scope > .pvz-grass-divider'
			);

			if (!divider) {
				divider = document.createElement('span');
				divider.className = 'pvz-grass-divider';
				divider.setAttribute('aria-hidden', 'true');
				wrapper.appendChild(divider);
			}
		});

		legacyHeadings = scope.querySelectorAll(
			'.skin-vector-legacy .mw-parser-output > h2'
		);

		Array.prototype.forEach.call(legacyHeadings, function (heading) {
			var divider;

			if (heading.closest('.mw-heading2')) {
				return;
			}

			heading.classList.add('pvz-grass-heading');

			divider = heading.querySelector(
				':scope > .pvz-grass-divider'
			);

			if (!divider) {
				divider = document.createElement('span');
				divider.className = 'pvz-grass-divider';
				divider.setAttribute('aria-hidden', 'true');
				heading.appendChild(divider);
			}
		});
	}

	function initGrassDividers() {
		var observer;

		installGrassDividers(document);

		observer = new MutationObserver(function (mutations) {
			mutations.forEach(function (mutation) {
				Array.prototype.forEach.call(
					mutation.addedNodes,
					function (node) {
						if (node.nodeType !== Node.ELEMENT_NODE) {
							return;
						}

						if (
							node.matches(
								'.mw-heading2, .mw-parser-output > h2'
							)
						) {
							installGrassDividers(node.parentNode);
							return;
						}

						installGrassDividers(node);
					}
				);
			});
		});

		observer.observe(document.body, {
			childList: true,
			subtree: true
		});
	}

	if (document.readyState === 'loading') {
		document.addEventListener(
			'DOMContentLoaded',
			initGrassDividers,
			{ once: true }
		);
	} else {
		initGrassDividers();
	}
}());


(function () {
	'use strict';

	var ACTION_OFFSET = 230;
	var SEARCH_WIDTH = 205;
	var SEARCH_DOWN_OFFSET = 5;
	var CONTENT_TOP = 24;

	function getCactionsParts() {
		var menu = document.getElementById('p-cactions');

		if (!menu) {
			return null;
		}

		return {
			menu: menu,
			label:
				document.getElementById('p-cactions-label') ||
				menu.querySelector('.vector-menu-heading'),
			checkbox: menu.querySelector(
				'input.vector-menu-checkbox, input[type="checkbox"]'
			),
			content: menu.querySelector('.vector-menu-content')
		};
	}

	function isCactionsOpen(parts) {
		if (!parts) {
			return false;
		}

		if (parts.checkbox && parts.checkbox.checked) {
			return true;
		}

		if (
			parts.menu.classList.contains('vector-menu-dropdown-active') ||
			parts.menu.classList.contains('pvz-cactions-open')
		) {
			return true;
		}

		if (parts.label) {
			return parts.label.getAttribute('aria-expanded') === 'true';
		}

		return false;
	}

	function closeCactions(parts) {
		if (!parts) {
			return;
		}

		if (parts.checkbox) {
			parts.checkbox.checked = false;
			parts.checkbox.dispatchEvent(
				new Event('change', { bubbles: true })
			);
		}

		parts.menu.classList.remove(
			'pvz-cactions-open',
			'vector-menu-dropdown-active'
		);

		if (parts.label) {
			parts.label.setAttribute('aria-expanded', 'false');
		}

		if (parts.content) {
			parts.content.setAttribute('aria-hidden', 'true');
		}
	}

	function handleCactionsClick(event) {
		var parts = getCactionsParts();
		var label;

		if (!parts) {
			return;
		}

		label = event.target.closest(
			'#p-cactions-label, #p-cactions > .vector-menu-heading'
		);

		if (label && isCactionsOpen(parts)) {
			event.preventDefault();
			event.stopImmediatePropagation();
			closeCactions(parts);
			return;
		}

		if (
			isCactionsOpen(parts) &&
			!event.target.closest('#p-cactions')
		) {
			closeCactions(parts);
		}
	}

	function syncV35Layout() {
		var content = document.querySelector('#content');
		var leftNavigation = document.getElementById('left-navigation');
		var rightNavigation = document.getElementById('right-navigation');
		var search = document.getElementById('pvz-content-search');
		var rightGap;
		var navigationTop;

		if (!content || !leftNavigation) {
			return;
		}

		rightGap = Math.max(
			0,
			window.innerWidth - content.getBoundingClientRect().right
		);

		navigationTop =
			leftNavigation.getBoundingClientRect().top +
			window.scrollY;

		if (!Number.isFinite(navigationTop)) {
			navigationTop = CONTENT_TOP;
		}

		document.documentElement.style.setProperty(
			'--pvz-content-right-gap',
			rightGap + 'px'
		);

		document.documentElement.style.setProperty(
			'--pvz-navigation-top',
			navigationTop + 'px'
		);

		if (rightNavigation) {
			rightNavigation.style.setProperty(
				'position',
				'absolute',
				'important'
			);
			rightNavigation.style.setProperty(
				'top',
				navigationTop + 'px',
				'important'
			);
			rightNavigation.style.setProperty(
				'right',
				(rightGap + ACTION_OFFSET) + 'px',
				'important'
			);
			rightNavigation.style.setProperty(
				'left',
				'auto',
				'important'
			);
			rightNavigation.style.setProperty(
				'display',
				'flex',
				'important'
			);
			rightNavigation.style.setProperty(
				'align-items',
				'flex-end',
				'important'
			);
			rightNavigation.style.setProperty(
				'justify-content',
				'flex-end',
				'important'
			);
			rightNavigation.style.setProperty(
				'width',
				'max-content',
				'important'
			);
			rightNavigation.style.setProperty(
				'margin',
				'0',
				'important'
			);
			rightNavigation.style.setProperty(
				'transform',
				'none',
				'important'
			);
		}

		if (search) {
			search.style.setProperty(
				'position',
				'absolute',
				'important'
			);
			search.style.setProperty(
				'top',
				(navigationTop + SEARCH_DOWN_OFFSET) + 'px',
				'important'
			);
			search.style.setProperty(
				'right',
				rightGap + 'px',
				'important'
			);
			search.style.setProperty(
				'left',
				'auto',
				'important'
			);
			search.style.setProperty(
				'width',
				SEARCH_WIDTH + 'px',
				'important'
			);
			search.style.setProperty(
				'max-width',
				SEARCH_WIDTH + 'px',
				'important'
			);
		}
	}

	function initV35Layout() {
		var observer;

		syncV35Layout();

		document.addEventListener(
			'click',
			handleCactionsClick,
			true
		);

		window.addEventListener(
			'resize',
			syncV35Layout,
			{ passive: true }
		);

		window.addEventListener(
			'orientationchange',
			syncV35Layout,
			{ passive: true }
		);

		observer = new MutationObserver(function () {
			window.requestAnimationFrame(syncV35Layout);
		});

		observer.observe(document.body, {
			childList: true,
			subtree: true
		});
	}

	if (document.readyState === 'loading') {
		document.addEventListener(
			'DOMContentLoaded',
			initV35Layout,
			{ once: true }
		);
	} else {
		initV35Layout();
	}
}());